Tutorial Oggetti Javascript (collegamenti) - Tecnologie dell'informazione e della comunicazione https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript Sun, 05 May 2024 22:26:27 +0000 Joomla! - Open Source Content Management it-it Javascript Message Box Tutorial: come creare un oggetto che interagisce con il documento https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript-intro https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript-intro

La creazione degli oggetti in Javascript è una necessità nelle applicazioni che superano le poche righe.

Tuttavia scrivere oggetti richiede inizialmente molta più fatica. Come ho scritto nel precedente articolo, questa maggior fatica iniziale viene ripagata in maggior facilità di manutenzione ed estensione dell'oggetto.

Voglio qui illustrare le differenze tra approccio procedurale e creazione di oggetti di una funzione semplicissima, che visualizza un messaggio a video e invoca una funzione quando si preme un tasto.

I 5 passi illustrano tutta la procedura, e vanno da un livello di complessità ridicolo fino ad affrontare diversi aspetti fondamentali dello sviluppo.

I primi 3 passi sono compatibili con IE, i successivi con (grossomodo) tutti i browser

Passo 1. Html + js + css

Partiremo da un singolo file html contenente il javascript, il css e l'html, che ha tre funzioni: una per mostrare il messaggio, e due invocate da ciascuno dei bottoni sul messaggio.

Passo 2. Creiamo l'oggetto msgBox

per la sola visualizzazione del messaggio. Verifichiamo che continua a funzionare

Passo 3. Completiamo la funzionalità dell'oggetto

Vediamo come passare gli eventi avanti e indietro dalla funzione chiamante alla funzione di risposta.Introduciamo un metodo ask (bottoni si/no) e un metodo tell (solo bottone ok)

Passo 4. Separiamo css, js, html in files separati, e aggiungiamo il supporto per firefox

Questo è lo step più importante.

A questo punto abbiamo 100 righe di javascript. Per mostrare un messaggio. Imbarazzante, direste.

Però abbiamo creato un oggetto che espone 2 funzioni, ask e tell, ma che è con pochissima fatica estendibile per gestire tutta la messaggistica di un programma, inclusi gli input di testo.

Passo 5: angoli arrotondati

Anche l'occhio vuole la sua parte.

Semplifichiamo anche l'uso spostando quanto possibile fuori dal file html principale.

 

Passo 6: finestra modale

Facciamo in modo che l'utente non possa interagire con il resto della pagina finché non ha cliccato un bottone.

Passo 7: tastiera

Facciamo funzionare anche la tastiera

Passo 8: timeout

Il timeout permette di specificare nelle funzioni un numero di secondi trascorsi i quali la finestra viene chiusa premendo il bottone predefinito.

Passo 9: Liste

La lista permette di proporre una lista di scelte all'utente che potrà poi sceglierne una.

Passo 10: Integrazione con l'applicazione

Testiamo la messagebox all'interno di una applicazione ajax. E vediamo quali modifiche sono necessarie

Passo 11: Allineamento

Un approccio per spostare la messageBox una volta creata

Passo 12: Multi-istanza

Rendiamo possibile creare più istanze della messageBox sulla stessa pagina. Quindi modifichiamo le callBack e usiamo qualche escamotage per risolvere semplicemente la questione.

Passo 13: Input di testo

Accettiamo l'input per un numero variabile di campi.

Passo 14: L'oggetto Tastiera a video

Disegno una tastiera a video per permettere l'input anche agli utenti con touch screen

Passo 16: Tastiere specializzate

Derivo (eredito) dall'oggetto Tastiera per creare tastiere "specializzate", numerica e alfa; dimostro come usarla senza la msgBox

Passo 18: Tastiera grafica per single-input e un po' di grafica...

Ora però facciamo qualche modifica per poter usare la nostra tastiera più rapidamente, diciamo con una riga di codice: derivo un nuovo oggetto, imposto una callback e... perdo 2 ore a disegnare tastini :-) . Sorry niente FF per questo passo.

Passo ?: Auto-creazione da XML

L'intento (ardito) è di creare una estensione del metodo request() che genericamente prenda un file XML, ne esamini una parte, derivi la struttura dal file stesso e ne proponga i valori come scelte possibili; quindi restituisca i valori incluso l'indice della scelta.

Passo ?: Validazione dell'input


 

Si d'accordo, questo è solo l'indice.

Le spiegazioni sono commentate all'interno del codice. Clic per scaricare. (Corso 1-18).
L'archivio è diviso in una cartella per ciascuna lezione. All'interno della stessa trovate msgBox.html - che potete usare per testarla.

Attenzione: msgBox e derivati sono sviluppati con l'intento di semplificare e uniformare la gestione della comunicazione con l'utente all'interno dell'applicazione HappyOrder. Vengono resi disponibili anche tramite questo corso perché crediamo che siano un semplice strumento per seguire l'evoluzione di un oggetto e capire quanto si risparmi nella manutenzione.

Che altro?

Appena iniziate a mettere in pratica questi esempi, procedete per punti "saldi". Appena ottenuto uno dei risultati che vi prefiggete, fate un commit sull'svn oppure zippate (con il rar si intende) la cartella coi sorgenti, e dategli un nome. Più tardi potrà tornarvi utile.

Tenete sempre sottomano il vostro codice funzionante. E' molto più veloce che consultare la documentazione!

E la documentazione, mettetevela nella homepage di firefox.

Risorse essenziali:

introduction to firebug

Mozilla Developer Center
http://developer.mozilla.org/en/JavaScript

MSDN JScript Language Reference
http://msdn.microsoft.com/en-us/library/yek4tbz0.aspx

]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Thu, 18 Sep 2008 14:14:52 +0000
Passo 1: html + js + css senza oggetti https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/33-passo-1-html-js-css-senza-oggetti https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/33-passo-1-html-js-css-senza-oggetti

HTML

Il primo passo è creare un layer <DIV> nel quale andremo a mettere testi e bottoni.

<DIV ID="msgBox">
    <SPAN ID="msgBoxtext">
        Ciao Gino bella giornata
    </SPAN>
    <br>
    <A ID="msgBox1" onclick="javascript:msgBoxYes()">Yes</A>
    <A ID="msgBox2" onclick="javascript:msgBoxNo()">No</A>
</DIV>

Css

Il tag <STYLE> permette di inserire inline (cioè dentro allo stesso file) una porzione di CSS: deve essere inserito all'interno della sezione <HEAD> (anche se poco cambia metterlo dentro al <BODY>

<STYLE>
    DIV#msgBox {width:450px; height:386px; background-color:yellow; color: navy; border: thin inset red;
        position: absolute; left: 150px; top:50px; text-align:center; margin:40px; display:none}
    DIV#msgBox A {text-decoration: none; font-size:120%; width:30%; height:10%; border:thin inset black; margin-top:200px}
    A#msgBox1 {font-weight: bold}
</STYLE>

(Lo so che fa schifo, concentriamci sul javascript e basta)

Script

Anche lo script è inline, con il tag <SCRIPT>.

Vediamolo nel dettaglio 

<SCRIPT LANGUAGE="JavaScript"> 

Assegno una variabile al layer che contiene il messaggio; così dovrò cercare il layer una volta sola, mentre i bottoni che chiudono la finestra di messaggio possono accedere direttamente alla variabile.

Qui sto contravvenendo a quanto detto nel decalogo: la manipolazione diretta dello stile.

Però lo sto facendo con il solo proposito di mostrare/nascondere un elemento; possiamo anche definire una classe "nascosto" e associare classi multiple ad un oggetto; ma non aggiungeremmo nulla alla manutenibilità del codice.

var msgBoxDiv 
    function showMessage(msg)
    {
         msgBoxDiv = document.getElementById("msgBox")
         msgBoxDiv.style.display = "block"
    }

Il message Box ha due bottoni; ciascuno invoca una funzione diversa, che provvede - come minimo - a chiudere (nascondere) il layer.

Per il posizionamento dei layers, display:block indica che il tag viene visualizzato su una nuova riga e seguito da un a capo; display:inline che segue il testo; display: none che non viene proprio visualizzato; è più comodo per il layout manipolare display: che non visibility:

function msgBoxYes()
    {
        alert('yes');
        msgBoxDiv.style.display = "none"

    }
    function msgBoxNo()
    {
        alert('no');
        msgBoxDiv.style.display = "none"
    }

</SCRIPT>

 

 

 


I file descritti in questo articolo si possono scaricare dall'introduzione

 

]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Fri, 19 Sep 2008 04:26:05 +0000
Passo 2: Oggetto in javascript https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/34-passo-2-oggetto-in-javascript https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/34-passo-2-oggetto-in-javascript

La creazione di oggetti in un linguaggio di programmazione è una pratica assolutamente fondamentale nella realizzazione di applicazioni complesse; ma come forma mentis aiuta farlo anche se costruite piccoli programmi di utilità.

In questo articolo discutiamo come creare tecnicamente un oggetto; tuttavia ben più importante è analizzare il problema e definire quali metodi e proprietà ed eventi debba avere questo oggetto per soddisfare al requisito di poter esistere indipendentemente dall'applicazione che lo usa.

In particolare, questo è indispensabile per effettuare sviluppo test-driven. Permette di raggiungere livelli di sicurezza notevoli; ma è anche il modo più facile per garantire che qualunque cosa riguardi l'oggetto non esce dai confini dell'oggetto; e quindi posso con tranquillità incorporare l'oggetto in progetti diversi, e aggiornarlo, senza dover cambiare altro codice fuori dall'oggetto.

Qui vogliamo concentrarci solo sulle differenze tra le funzioni che abbiamo creato nel passo 1, e la loro trasformazione in oggetto.

L'oggetto viene instanziato (creato) da

var msgBox = new _msgBox()

dove _msgBox() è una funzione normalissima all'interno della quale è possibile definire alcune proprietà usando l'oggetto this.

// --------------------- _msgBox --------------------------------
// L'oggetto _msgBox, che verrà istanziato nella variabile msgBox.
function _msgBox()
{
    // le proprietà dell'oggetto si definiscono usando la parola riservata this.
    this.divMsg;
    this.message = "";
    this.button1 = "Yes";
    this.button2 = "No";
    this.button1Result = true;
    this.button2Result = false;
}

Ho creato alcune proprietà che saranno utili più avanti.

Per quanto riguarda i metodi, benché sia possibile dichiararli in-line, è francamente molto più semplice e ordinato modificare il prototype dell'oggetto appena creato: quindi

// Le funzioni invece si definiscono più comodamente con prototype.
_msgBox.prototype.ask = function (msgHTML)
{
    this.divMsg = document.getElementById("msgbox")
    this.button1 = "Yes";
    this.button2 = "No";
    this.button1Result = true;
    this.button2Result = false;
    this.divMsg.firstChild.innerHTML = msgHTML;
    this.divMsg.style.display = "block"
}

A questo punto sarà possibile invocare la nuova funzione (l'oggetto è già istanziato): quindi

<a href="https://tmg.it/#" onclick="javascript:msgBox.ask('dormi?')">dormi?</a><br>

 

 


I file descritti in questo articolo si possono scaricare dall'introduzione]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Fri, 19 Sep 2008 04:30:34 +0000
Passo 3: Completiamo la funzionalità base https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/35-passo-3-completiamo-la-funzionalita-base https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/35-passo-3-completiamo-la-funzionalita-base

Il funzionamento di un oggetto richiede che anche la comunicazione iniziata dall'oggetto verso il programma chiamante sia gestita dall'interno dell'oggetto. In inglese si usa il termina CALLBACK per indicare una seconda funzione passata come parametro da una prima funzione, e che verrà invocata dalla prima funzione quando si saranno verificati eventi.

L'analogo in un linguaggio di programmazione che dispone di una IDE è il controllo bottone, che ha una proprietà onclick: là collegheremo una nostra funzione. Al verificarsi dell'evento la funzione collegata alla proprietà onclick verrà invocata.

In javascript non abbiamo grossi problemi a passare la funzione, basta passarla per nome.

Per comodità la registro in una variabile.

 

Quindi qui ho definito una prima procedura che collega gli eventi ai bottoni: e già che c'è gli assegna anche i valori standard per il testo ed il messaggio di risposta che dovranno fornire; Quindi assegna come proprietà dell'oggetto     this.callBackFunction la funzione che andrà invocata quando l'utente chiude il message box.

Il funzionamento è piuttosto lineare: assegno a buttonXDiv il <DIV> corrispondente, e lo trovo usando il suo ID; 

_msgBox.prototype.attachEvents = function (aCallBackFunction)
{
    if (!this.button1Div)
        this.button1Div = document.getElementById("msgBox1");
    if (!this.button2Div)
        this.button2Div = document.getElementById("msgBox2");

Questa è simpatica: questa istruzione può tradursi: if (this.button1) return "inline" else return "none". Molto sintetica, permette di ridurre le dimensioni del codice aumentando la leggibilità. Se ne usate più di una nella stessa riga, commentate e spiegate cosa state facendo: altrimenti lo capirete solo voi.

    this.button1Div.style.display=(this.button1?"inline":"none");
    this.button2Div.style.display=(this.button2?"inline":"none");
    this.callBackFunction = aCallBackFunction

    // assegnare testi e funzioni ai pulsanti. L'evento deve prima essere de-assegnato altrimenti man mano che questa funzione viene eseguita, mi ritroverò ad eseguire l'evento onclick 2,3,4 volte per ciascun click.

 

    if (this.button1)
    {
        this.button1Div.detachEvent('onclick', this.buttonEvent);
        this.button1Div.attachEvent('onclick', this.buttonEvent);
        this.button1Div.msgResult = this.button1Result;
    }
    if (this.button2)
    {
        this.button2Div.detachEvent('onclick', this.buttonEvent);
        this.button2Div.attachEvent('onclick', this.buttonEvent);
        this.button2Div.msgResult = this.button2Result;
    }
}

 

 


I file descritti in questo articolo si possono scaricare dall'introduzione]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Fri, 19 Sep 2008 04:37:37 +0000
Passo 4: separiamo + firefox https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/36-passo-4-separiamo-firefox https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/36-passo-4-separiamo-firefox

A questo punto c'è un po' di codice, vediamo di dare una struttura ragionevole al nostro "progetto". Creeremo un file per lo stile, uno per il javascript che contiene tutta la logica del msgBox, uno per l'html.

Javascript

Il codice javascript (senza i tag <SCRIPT>) può essere copiato in questo file (msgbox.js); per collegarlo al mio file HTML, inserirò il tag

<SCRIPT type="text/javascript" src="https://tmg.it/msgbox.js"></SCRIPT>

CSS

Altrettanto vale per il css: le regole vengono copiate in un file esterno (msgbox.css) quindi facciamo riferimento a questo file dall'header del file HTML inserendo:

<LINK href="https://tmg.it/msgbox.css" rel="stylesheet" type="text/css"> 

HTML

E l'HTML? quello che resta :-) 

Firefox

Ora possiamo estendere un po' le funzionalità del nostro message box per includere supporto per firefox, e separare un po' di logica ripetuta in funzioni dedicate.

Il DOM è unico, ma l'implementazione delle funzioni che servono per manipolarlo è un po' diversa tra i vari browser; Per il momento le differenze son minime, quindi possiamo gestirle direttamente; in ambito applicativo, meglio utilizzare un framework che si occupi per noi di gestire queste differenze (e che qualcun altro tenga aggiornato)!!! Ho dovuto modificare due mesi fa una pagina scritta nel '97 perché - per quanto uno cerchi di essere lungimirante - i framework di riferimento evolvono e cambiano.  Il prossimo capitolo è dedicato a questi framework.

Nota bene: quando scrivo Firefox, si applica a Google Chrome, Opera e Safari normalmente. Non ho controllato su questi browser tuttavia. Nel 95% dei casi è comunque sufficiente gestire due soli casi, internet explorer e "gli altri". 

Scuse ufficiali

Ho rinominato un paio di funzioni e variabili in italiano. attachEvents() è diventato collegaEventi(); poi ho creato una funzione collegaEvento() che gestisce le differenze da Firefox e IE.

_msgBox.prototype.collegaEvento = function (aElement, aEventName, aEvent, aMsgResult)
{
// aElement: l'elemento cui collegare l'evento
// aEventName: "click" per esempio
// aEvent: la funzione che deve essere invocata quando si verifica aEventName
// aMsgResult: il risultato di questo bottone.

// Ora devo collegare gli eventi. Devo gestire la differenza tra firefox e ie ecc.

aElement.msgResult = aMsgResult;
if (aElement.detachEvent) // per sapere se esiste - su firefox non esiste
{ // ie
aElement.detachEvent('on'+aEventName, aEvent);
aElement.attachEvent('on'+aEventName, aEvent);
}
else
{ // other browsers
aElement.removeEventListener(aEventName, aEvent, false);
aElement.addEventListener(aEventName, aEvent, false);
}
}

_msgBox.prototype.collegaEventi = function (aCallBackFunction)
{
this.divMsg = document.getElementById("msgBox")

if (!(this.button1Div instanceof Object))
this.button1Div = document.getElementById("msgBox1");
if (!(this.button2Div instanceof Object))
this.button2Div = document.getElementById("msgBox2");

this.button1Div.style.display=(this.button1?"inline":"none");
this.button2Div.style.display=(this.button2?"inline":"none");
this.callBackFunction = aCallBackFunction

// assegnare testi e funzioni ai pulsanti.
if (this.button1)
{
this.collegaEvento(this.button1Div, 'click', this.buttonEvent, this.button1Result);
}

if (this.button2)
{
this.collegaEvento(this.button2Div, 'click', this.buttonEvent, this.button2Result);
}
}

Anche nella funzione buttonEvent è necessario gestire la differenza tra ie e firefox:

_msgBox.prototype.buttonEvent = function(e)
{
    // Questo evento viene invocato dal bottone cliccato yes no ecc.
    // quindi non ha un accesso diretto all'istanzqa dell'oggetto dall'interno
    // e bisogna usare il riferimento assoluto
    msgBox.divMsg.style.display = "none"
    if (e instanceof Object)
    { // firefox
        msgBox.callBackFunction(e.target.msgResult)
    }
    else
        msgBox.callBackFunction(event.srcElement.msgResult);

}

Con queste due funzioni abbiamo finito di separare il codice.

E' evidente come per aggiungere nuove funzionalità posso concentrarmi sulle mie funzioni usando le funzioni generiche collegaEvento(). Nelle funzioni interne di un oggetto, può essere conveniente usare un paio di parametri in più per lasciare spazio alle estensioni future; mentre per i metodi esposti (pubblici) è fondamentale permettere il funzionamento anche con un numero minimo di parametri, per semplificarne l'uso all'interno del codice. 

 


I file descritti in questo articolo si possono scaricare dall'introduzione]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Fri, 19 Sep 2008 04:51:34 +0000
Passo 5: angoli arrotondati https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/37-passo-5-angoli-arrotondati https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/37-passo-5-angoli-arrotondati

Se vogliamo usare il nostro messageBox sarà necessario renderlo presentabile. Rimanendo facile da usare.

Per questo desidero che abbia gli angoli arrotondati, e che sia scalabile a piacere.

Le tecniche per avere gli angoli arrotondati si riducono a :

  • Usare un browser che supporti CSS3
  • Usare una tabella per posizionare i vari pezzi dello sfondo (9 pezzi necessari)
  • Usare un foglio di stile e vari elementi div cui associare un minimo di 4 pezzi
  • Usare un foglio di stile e vari elementi cui associare parti diverse della stessa immagine (riducendo notevolmente il tempo di download, e la grafica viene mostrata in un unico momento, e non un pezzo alla volta)

Scelgo l'ultima.

Una implementazione facile è descritta in Even More Rounded Corners With CSS. Useremo questa con piccole modifiche.

Cosa vogliamo vedere

Prima di tutto vediamo il risultato in azione:

Per ottenerlo, è sufficiente inserire questo html:

<div ID="msgBoxDiv" class="dialog color_red">
<div class="content">
<div class="wrapper">
<div class="t"></div>
<div id="msgBoxHeader" class="hd" >
Domanda
</div>
<div class="bd">
<p id="msgBoxText">Messaggio</p>
</div>
<div class="ft">
<p><A ID="msgBox1">Si</A>
<A ID="msgBox2">No</A></p>
</div>
</div>
</div>
<div class="b"><div></div></div>
</div>

ed il css (che trovate nel pacchetto da scaricare). Mi soffermo un momento sul sistema usato per ancorare l'immagine in punti diversi:

.dialog .content,
.dialog .t,
.dialog .b,
.dialog .b div {
background:transparent url(dialog-blue.png) no-repeat top right;
_background-image:url(dialog-blue.gif);
}
.dialog .t {
background-position:top left;
}
.dialog .b {
background-position:bottom right;
}

 

e così via. In sostanza definisco una volta sola l'immagine per tutte le classi dei bordi; quindi per ciascuna modifico solo background-position.

Compatibilità con i browser

Ora vediamo come viene su chrome:

e su ie6? beh c'è il problema dei PNG a 24 bit, è solo dal 2000 che si usano in fin dei conti... come poteva un browser uscito nel 2003 già supportarli?

Notate la differenza? La trasparenza è sparita! Come si fa ad ottenere un risultato così fantastico?

Semplice: un trucchetto.

 background:transparent url(dialog-blue.png) no-repeat top right;
_background-image:url(dialog-blue.gif);
una delle tante funzioni assurde di ie, specifico una immagine con _background-image (nota il "_"); questo viene ignorato ovviamente dagli altri browser.

Integriamolo con l'oggetto

Le modifiche da fare sono veramente poche.

Prima di tutto, visto che l'obiettivo è di avere una funzione msgBox e non di scrivere markup, mettiamo l'html nel codice di inizializzazione del bottone;

function _msgBox(aColor)
{
this.divMsg = null;
this.message = "";
this.button1Div = null;
this.button2Div = null;
this.divHeader = null;
this.divContent = null;

this.button1 = "Si";
this.button2 = "No";
this.button1Result = true;
this.button2Result = false;
this.callBackFunction = null;
this.color=aColor;

this.divMsg = document.getElementById("msgBoxDiv")
if (this.divMsg==null)
{
var aMsgBoxContent =
'<div ID="msgBoxDiv" class="dialog color_'+this.color+'">'+
' <div class="content">'+
' <div class="wrapper">'+
' <div class="t"></div>'+
' <div id="msgBoxHeader" class="hd" >'+
' Domanda'+
' </div>'+
' <div class="bd">'+
' <p id="msgBoxText">Messaggio</p>'+
' </div>'+
' <div class="ft">'+
' <p><A ID="msgBox1">Si</A>'+
' <A ID="msgBox2">No</A></p>'+
' </div>'+
' </div>'+
' </div>'+
' <div class="b"><div></div></div>'+
'</div>';
document.body.innerHTML += aMsgBoxContent
this.divMsg = document.getElementById("msgBoxDiv")
}
}

Questa funzione prende un parametro. Il colore dello sfondo da utilizzare.Il secondo foglio di stile, dialog-variants.css, contiene esclusivamente le diverse immagini per i vari stili.

 

Visto che interagisce con l'innerHTML,

dovremo sincerarci che venga eseguito dopo che la pagina è caricata:

var msgBox

function initBox()
{
msgBox = new _msgBox('red')
};
window.onload = initBox;

Questa è tutta la configurazione necessaria per poterlo usare. 

Inoltre saranno sempre presenti nella intestazione del file html:

  • <link rel="stylesheet" href="https://tmg.it/msgbox/msgbox.css?u=1" media="screen" >
  • <link rel="stylesheet" href="https://tmg.it/msgbox/dialog-variants.css" media="screen" />
  • <SCRIPT type="text/javascript" src="https://tmg.it/msgbox/msgbox.js"></SCRIPT>

 

Ora con tutti questi test,mi sono stancato di premere Ok sull'alert. Spostiamo l'output su una textarea.

Visto che i files sono diventati tanti, li ho spostati nella cartella msgbox (la fantasia è la mia prima dote :-P


I file descritti in questo articolo si possono scaricare dall'introduzione

L'archivio nella pagina introduzione è il più aggornato e contiene i files di tutte le lezioni

]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Wed, 15 Oct 2008 19:10:10 +0000
Passo 6: finestra modale https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/38-passo-6-finestra-modale https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/38-passo-6-finestra-modale

Prima di poter usare la nostra message box dobbiamo renderla modale.

Una finestra modale è una finestra che non restituisce il controllo all'applicazione finché non viene chiusa dall'utente. E' un tipico esempio la domanda "Procedo" con i bottoni "Si" e "No". La funzione attende che la finestra di dialogo venga chiusa per procedere.

 Messagebox modale

Nel nostro caso abbiamo dovuto definire le funzioni di callback per ottenere questo risultato.

Però dobbiamo anche impedire che l'utente interagisca con il resto della pagina finché non ci ha dato una risposta. Per farlo, il modo più simpatico è creare un layer grande quanto la pagina da mettere dietro alla nostra message box. in questo modo i clic saranno impossibili.

 

 

Il layer ha il background dello stesso colore della message box ed è semi trasparente. Dovremo posizionarlo tramite la funzione di creazione _msgBox()

	this.divMsgModal = document.getElementById("msgModalDiv")
this.divMsgBox = document.getElementById("msgBoxDiv")

metto il layer modale fullscreen; innerHeight&width non sono disponibili su IE.
ma offsetWidth e height hanno un significato diverso tra i browser.
quindi uso il costrutto (condizione?true:false) per valorizzare le mie variabili
cwidth e cheight che indicano le dimensioni dell'area visibile.

	var cwidth = (window.innerWidth>0?window.innerWidth: document.body.offsetWidth)
var cheight = (window.innerHeight>0?window.innerHeight: document.body.offsetHeight)
this.divMsgModal.style.width = cwidth;
this.divMsgModal.style.height = cheight;

Per ottenere la trasparenza, uso un comando diverso per IE e firefox:

		opacity: 0.30; /* css2 */
filter:alpha(opacity=30); /* IE */

Oltre a posizionare il layer devo anche centrare il box del messaggio:  

	this.divMsgBox.style.left = parseInt(cwidth)/2-parseInt(this.layerWidth)/2+'px';
this.divMsgBox.style.top = parseInt(cheight)/2-parseInt(this.layerHeight)/2+'px';

 


I file descritti in questo articolo si possono scaricare dall'introduzione]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Tue, 28 Oct 2008 10:54:13 +0000
Passo 7: tastiera https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/39-passo-7-tastiera https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/39-passo-7-tastiera

A questo punto proviamo ad usare il nostro message box, e ci accorgiamo che non reagisce affatto alla tastiera.

Collegare gli eventi

Il mio obiettivo è quello di catturare l'input da tastiera mentre la finestra è visualizzata, e ripristinare l'eventuale handler precedente quando l'utente chiude la finestra.

Per prima cosa connetto l'handler insieme alle funzioni dei pulsanti:

_msgBox.prototype.collegaEventi = function (aCallbackFunction)
{
[...]
    // assegnare testi e funzioni ai pulsanti.
  if (this.button1!="")
{
this.oldKeyPressHandler=document.onkeypress;
document.onkeypress = msgBox.handleKeyboard

Questo mi connetterà l'evento ogni volta che c'è  almeno un bottone. E imposterà oldKeyPressHandler al gestore precedente.

La funzione di callback è ora divisa tra interpretazione del messaggio (buttonclick e keypress) ed elaborazione:

_msgBox.prototype.handleCallback = function(aMsgResult)
{
msgBox.divMsgModal.style.display = "none"
msgBox.divMsgBox.style.display = "none"

document.onkeypress = msgBox.oldKeyPressHandler
msgBox.oldKeyPressHandler=null

msgBox.callbackFunction(aMsgResult)
}

Qui riassegno il gestore originale dell'evento tastiera.

Gestire gli eventi

La funzione di gestione del mouse quindi, usando la nuova callback generica, diventa:
_msgBox.prototype.buttonEvent = function(e)
{
    // Questo evento viene invocato dal bottone cliccato yes no ecc.
    // quindi non ha un accesso diretto all'istanza dell'oggetto dall'interno
    // e bisogna usare il riferimento assoluto

    if (e instanceof Object)
    { // firefox
        msgBox.handleCallback(e.target.msgResult)
    }
    else
        msgBox.handleCallback(event.srcElement.msgResult);
}

Notare che non uso this.handleCallback ma msgBox.handleCallback perché dall'interno di un handler di evento non posso accedere all'oggetto originale.

Anche nel caso di interpretazione del comando da tastiera i browser si comportano in maniera diversa:

quindi la funzione handleKeyboard() dovrà:

_msgBox.prototype.handleKeyboard = function(e)
{
  if(!e) e=window.event;
key = e.keyCode ? e.keyCode : e.which;

    switch (key)
    {
        case 13: //enter
        case 32: //spazio
        case 115:// s
        case 83: // S
        case 121:// y
        case 89: // Y
            msgBox.handleCallback(msgBox.button1Result);
            break;
        case 27: //ESC (non viene visto da firefox)
        case 110://n
        case 78: //N
            msgBox.handleCallback(msgBox.button2Result)
            break;
    }
}

Altra nota curiosa alla sintassi: IE supporta 

case 13,32,115:

Ma firefox no.


I file descritti in questo articolo si possono scaricare dall'introduzione]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Tue, 28 Oct 2008 12:54:41 +0000
Passo 8: timeout https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/40-passo-8-timeout https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/40-passo-8-timeout
Per prima cosa implementiamo un timeout.
Mi serve principalmente per quelle domande di conferma che hanno una risposta predefinita che si usa al 90%...
 

Ciascuna funzione  di visualizzazione (ask, tell) include in fondo:

    if (arguments.length > 3)
    {
        this.doTimeout(okTimeoutSeconds);
    }
Quindi passando un parametro in più, ovvero il timeout in secondi, si attiva il timeout.
 
Gestisco tutto (setup, display dei secondi restanti, e chiusura) da una funzione sola:
 
_msgBox.prototype.doTimeout = function (okTimeoutSeconds)
{
    if (arguments.length>0)
    {
        // faccio partire il timeout. okTimeoutSeconds sono i secondi trascorsi
        // i quali verrà premuto il primo bottone automaticamente.
        this.okTimeoutProgress = okTimeoutSeconds;
    }
    if (this.okTimeoutProgress <= 0)
    {
        this.handleCallback(msgBox.button1Result);
    }
    else
    {
        this.button1Div.innerHTML = this.button1+'...'+this.okTimeoutProgress--;
        clearTimeout(this.okTimeoutID);
        this.okTimeoutID = setTimeout("msgBox.doTimeout()",1000);
    }
}

I file descritti in questo articolo si possono scaricare dall'introduzione
]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Tue, 28 Oct 2008 14:06:15 +0000
Passo 9: Liste https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/41-passo-9-liste https://tmg.it/articoli-tecnici/tutorial-oggetti-javascript/41-passo-9-liste

 

 

Affrontiamo ora un più gravoso compito: una messagebox che offra una serie di possibilità tra le quali scegliere.

Che dovrà chiaramente restituire un riferimento alla scelta fatta nella risposta.

 

Creo una nuova funzione, listChoose(), che accetta come parametro un array. Nella risposta affermativa (button1) restituirò l'indice scelto o -1 se non è stato scelto nessun indice.

 

 

 

 

 

 

 

_msgBox.prototype.listChoose = function (msgHTML, aCallbackFunction, msgTitle, 
okTimeoutSeconds, lista)
{
/*
per disattivare il timeout, passare -1 come valore di okTimeoutSeconds
*/
with (this)
{
button1 = "Ok";
button2 = "Annulla";
button1Result = true;
button2Result = false;
message = msgHTML;
collegaEventi(aCallbackFunction)
divContent.innerHTML = msgHTML;

if (arguments.length < 5)
divContent.innerHTML += '<br>Numero di parametri errato'

Eccoci alla parte saliente (il disegno della lista). Ho scelto di usare una SELECT, ma nulla vieta di disegnare dei radiobuttons o dei controlli dedicati, anche una tabella può fare al caso nostro. Questa è però sicuramente la soluzione più semplice:


// ora spizzo la lista. Ho bisogno di far scegliere una voce. La soluzione
// più simpatica è una bella SELECT visualizzata già aperta
var aSelect = '<br><SELECT id="selectList" size=8>';

if (lista instanceof Array)
{
for (var i=0; i<lista.length ;i++ )
{
aSelect += '<OPTION VALUE="'+i+'" >'+lista[i]+'</OPTION>';
}
}

aSelect += '</SELECT>';
divContent.innerHTML += aSelect;

selectBox = document.getElementById('selectList');

divHeader.innerHTML = msgTitle
divMsgModal.style.display = "block"
divMsgBox.style.display = "block"

doTimeout(okTimeoutSeconds);
}
}

La funzione chiamante è responsabile della creazione e distruzione della lista.

function lista()
    {
        var arrScelte = new Array ("Giove", "Marte", "Europa",
"una qualche altra luna di Giove",
"Venere", "Plutone", "Terra", "Luna", "Mercurio", "Urano", "Saturno",
"Una qualche luna di Saturno");
       msgBox.listChoose('Su che pianeta vorresti vivere?',elaboraRisposta,
'una domanda di cultura generale', -1, arrScelte)   
    }

E infine il foglio di stile, usa il trucchetto della trasparenza per dare una parvenza di grafica

SELECT#selectList {font-size:120%; opacity:0.8; filter: alpha(opcity=80);width:80%}
 

 

 


I file descritti in questo articolo si possono scaricare dall'introduzione

 

]]>
r.zorn@tmg.it (Riccardo Zorn) Tutorial Oggetti Javascript Tue, 28 Oct 2008 14:39:59 +0000