venerdì 27 giugno 2008

Mootools. Creare elementi DOM

L'esame del sorgente della classe QScroller ci porta a spendere qualche parola sulle funzioni di Mootools dedicate alla creazione di elementi DOM.

Riporto di seguito solo le parti di sorgente di cui parleremo

var QScroller = new Class({
  /* ... */
  initialize: function(wrapper,options) {
    /* ... */     
    this.slideOut = new Element('div').setStyles({ (1)
      position: 'absolute',
      overflow: 'hidden',
      top: 0,
      left: 0,
      width: this.wrapper.getStyle('width'),
      height: this.wrapper.getStyle('height')
    }).injectInside(this.wrapper);

    this.slideIn = this.slideOut.clone(); (2)
    this.slideIn.injectInside(this.wrapper);        
    /* ... */
  },
  /* ... */
});
QScroller.implement(new Options, new Events);

(1) Con questa istruzione creiamo un nuovo elemento div, ne impostiamo alcuni attributi con la funzione setStyles() (già incontrata nell'articolo precedente) e lo aggiungiamo come figlio di this.wrapper (l'elemento contenitore anch'esso visto in precedenza) con la funzione injectInside().

Come si vede, una volta che un elemento è stato creato è necessario inserirlo nel documento. Inserire l'elemento in un altro preesistente con la funzione injectInside() è uno dei modi per farlo, ma non l'unico: esistono infatti anche le funzioni injectBefore() e injectAfter() di cui vediamo subito un esempio.

Consideriamo questa porzione di documento html

<div id="elemento0"></div>

Dopo l'esecuzione di questo codice Javascript

<script type="text/javascript">
<!--
window.addEvent('domready', function() {
  var el = $('elemento0');
  var e = new Element('div', {id: 'elemento1'});
  e.injectInside(el);
  var e = new Element('div', {id: 'elemento2'});
  e.injectBefore(el);
  var e = new Element('div', {id: 'elemento3'});
  e.injectAfter(el);
});
//-->
</script>

ecco la struttura del documento visualizzata dal Dom Inspector di Firefox che rende bene l'idea del risultato prodotto dallo script.

Continuiamo con il sorgente di QScroller

(2) L'istruzione clone(), come il nome suggerisce, crea una copia identica di un elemento. I due attributi della classe slideIn e slideOut funzioneranno come elementi di 'transito' per il contenuto delle slide che saranno animate con effetto di scorrimento.

I dettagli devono essere rimandati a quando passeremo dal codice di inizializzazione alle funzioni che svolgono i compiti effettivi per cui è stata sviluppata la classe.

Avevo detto che non sarebbe stata una cosa tanto veloce! I più impazienti hanno già a disposizione il sorgente completo da esaminare.

venerdì 20 giugno 2008

Mootools. Elementi ed eventi

Prima di proseguire con l'esame della classe QScroller ecco il link per scaricare il pacchetto completo con gli esempi. Decomprimete l'archivio in una cartella del vostro sito web (o localhost) e aprite index.html con il browser. Tenendo a portata di mano il sorgente della classe (file qscroller.js) sarà più facile seguire il discorso.

Continuiamo la spiegazione della funzione initialize() che, ricordo, viene invocata automaticamente alla creazione di un'istanza della classe.

var QScroller = new Class({
  options: { 
    slides: 'qslide',
    direction: 'h',
    duration: 3000,
    auto: false,
    delay: 1000,
    transition: Fx.Transitions.linear
  },
  initialize: function(wrapper,options) { 
    this.setOptions(options); 
    this.wrapper = $(wrapper); (1)
    this.wrapper.setStyles({ (3)
      position: 'relative',
      overflow: 'hidden'
    });
    this.wrapper.addEvent('mouseenter', (4)
      this.fireEvent.pass('onMouseEnter',this));

    this.wrapper.addEvent('mouseleave', 
      this.fireEvent.pass('onMouseLeave',this));
    /* ... */
  },
  /* ... */
});
QScroller.implement(new Options, new Events);

var opt = { 
  auto:true,
  onMouseEnter: function(){this.stop();}, (5)
  onMouseLeave: function(){this.play();}
}
var scroller = new QScroller('qscroller1',opt); (2)

Uno dei maggiori punti di forza di Mootools è la facilità con cui consente di accedere e modificare gli elementi DOM o crearne nuovi dinamicamente. Le funzioni dedicate a questo scopo sono molte, vedremo solo quelle che sono utilizzate nel codice della classe.

La prima che incontriamo è la funzione $ (l'hanno chiamata semplicemente così) che ritorna un elemento DOM il cui ID passiamo come argomento. Nel nostro caso

(1) Salviamo come proprietà wrapper della classe QScroller l'elemento DOM di ID qscroller1 (vedi (2) )

Fatto questo possiamo modificare gli attributi dell'elemento (che come vedremo è il contenitore della nostra animazione)

(3) Impostiamo gli attributi position ed overflow. La funzione setStyle() riceve come argomento un oggetto letterale che contiene le coppie attributo/valore che dobbiamo impostare ( {attributo1: 'valore1', attributo2: 'valore2', ... } ).

Anche solo da queste poche righe penso si possa intuire la facilità con cui Mootools permette di modificare dinamicamente con Javascript il contenuto o l'aspetto di una pagina web.

(4) Come spesso succede in Mootools una sola riga di codice si traduce in una lunga spiegazione.

a) con addEvent() aggiungiamo a this.wrapper (ricordo, l'elemento di ID qscroller1) un event listener per l'evento mouseenter.

b) quando il puntatore del mouse entra (mouseenter appunto) nell'area dell'elemento attiveremo (con fireEvent()) l'evento onMouseEnter della classe QScroller.

c) il che significa che sarà eseguito il codice della funzione onMouseEnter() che abbiamo passato in options (5).

Con questo meccanismo consentiamo agli utenti della classe di personalizzare il codice eseguito al verificarsi di un determinato evento senza dover intervenire sul codice della classe stessa.

Resterebbe da vedere l'uso di pass() e soprattutto perché sia necessario in questo caso, ma spero non si offenda nessuno, rimando la spiegazione ad un'altra volta! L'argomento è complesso e questa breve serie di articoli non vuole certo essere una guida completa a Mootools.

mercoledì 11 giugno 2008

Joomla 1.5. Tabs in contenuti e moduli

L'uso di tabs (o linguette, tipo schedario o rubrica telefonica) come strumento per consentire all'utente di navigare facilmente tra diverse 'pagine' di informazioni è un modello di interfaccia che si riscontra frequentemente su molti siti web.

Posto che ce ne sia bisogno, ecco un esempio dall'home page di Yahoo.

In Joomla 1.5 le tabs si possono facilmente creare con apposite funzioni del framework. L'unico problema è che le tabs sono di solito utilizzate nel backend, per averle nel frontend è necessario un po' di lavoro. Spiego il procedimento passo passo, stile ricetta della nonna.

Per prima cosa installare il plugin Jumi che ci servirà per facilitare l'inserimento di codice html e php in un contenuto. Il plugin va attivato da Gestione plugin.

Creare con un programma FTP una cartella jumi_includes all'interno della stessa cartella dove è installato Joomla.

Poi creare un file tabs.css. Siccome è difficoltoso fare il copia e incolla dal testo, ho voluto provare pastebin.com: fate click sui nomi dei file che saranno via via citati nell'articolo per vederne una versione con sintassi evidenziata scaricabile o copiabile facilmente.

dl.tabs {
float:left;
margin:10px 0pt -1px;
z-index:50;
}
dl.tabs dt {
background:#F0F0F0 none repeat scroll 0%;
border-left:1px solid #CCCCCC;
border-right:1px solid #CCCCCC;
border-top:1px solid #CCCCCC;
color:#666666;
float:left;
margin-left:3px;
padding:4px 10px;
}
dl.tabs dt.open {
background:#F9F9F9 none repeat scroll 0%;
border-bottom:1px solid #F9F9F9;
color:#000000;
z-index:100;
}
div.current {
border:1px solid #CCCCCC;
clear:both;
padding:10px;
}
div.current dd {
margin:0pt;
padding:0pt;
}

Questi attributi sono copiati dal foglio di stile del template predefinito del backend e servono a determinare l'aspetto delle tabs. Fare l'upload di tabs.css in jumi_includes.

Creare un file tabs.php con questo contenuto

<?php
JHTML::stylesheet('tabs.css','jumi_includes/');

Questa istruzione serve ad includere nell'intestazione del documento html il file css creato in precedenza. Il percorso del file css è relativo alla cartella di Joomla. Per esempio supponendo che la pagina principale del vostro sito sia raggiungibile con

http://www.example.com/joomla

come risultato della esecuzione di JHTML::stylesheet() con gli argomenti visti sopra, tra <HEAD> e </HEAD> della pagina trovereste

<link rel="stylesheet" href="/joomla/jumi_includes/tabs.css" 
type="text/css" />

È una funzione da tenere a mente perché utilissima quando si sviluppano moduli e componenti che necessitano di inserire propri fogli di stile nell'intestazione del documento html.

Continuiamo con il codice

jimport('joomla.html.pane');

Include la definizione della classe JPane che utilizzeremo subito e inserisce (sempre tra <HEAD> e </HEAD>) il codice Javascript necessario al funzionamento delle tabs. Non vedremo questo codice in dettaglio, fa parte di Joomla e funziona e questa è l'unica cosa che ci interessa.

$tabs = &JPane::getInstance('tabs');
echo $tabs->startPane('test-tabs');

Otteniamo un'istanza dell'oggetto che ci serve e iniziamo il gruppo di tabs con ID test-tabs. Potete scegliere l'ID che preferite, ma se si vogliono creare più gruppi di tabs sulla stessa pagina è importante che ognuno abbia un ID differente.

echo $tabs->startPanel('Tab1', 'test-tab1');
?>
<p>Contenuto tab1</p>
<p>qwerty</p>
<?php
echo $tabs->endPanel();

Contenuto della prima tab. Mi sembra abbastanza intuitivo: inseriamo il codice html che vogliamo tra startPanel() e endPanel(). Gli argomenti da passare al primo metodo sono il titolo visibile della tab e un ID che anche in questo caso deve essere univoco.

echo $tabs->startPanel('Tab2', 'test-tab2');
?>
<p>Contenuto tab2</p>
<?php
echo $tabs->endPanel();
echo $tabs->startPanel('Tab3', 'test-tab3');
?>
<p>Contenuto tab3</p>
<?php
echo $tabs->endPanel();
echo $tabs->endPane();
?>

Allo stesso modo si creano la seconda e la terza tab e si chiude il gruppo con endPane()

Fare l'upload di tabs.php in jumi_includes.

A questo punto create un articolo e nel contenuto inserite il comando Jumi

{jumi [jumi_includes/tabs.php]}

Pubblicate e visualizzate l'articolo nel frontend. Il risultato dovrebbe essere questo.

Considerando che possiamo inserire codice html come contenuto dei tabs penso sia chiaro che si possono ottenere effetti interessanti.

Ma potrebbe essere anche più interessante visualizzare dei moduli a nostra scelta in un gruppo di tabs. Si può fare, ecco la seconda ricetta.

Per prima cosa aprire con un editor di testi il file templateDetails.xml nella cartella del proprio template. Aggiungere una nuova posizione tabs nella sezione positions

<positions>
...  
<position>tabs</position>
</positions>

Al posto dei puntini avete le altre posizioni previste dal template: quelle non vanno toccate (precisazione forse inutile).

Poi effettuare il login al backend di Joomla! ed entrare in Gestione moduli. Aprire mod_latestnews (modulo Ultime Notizie), se non è nella lista dei moduli crearlo con Nuovo. Nella schermata di modifica del modulo impostare

  • Posizione: tabs
  • Assegnazione Menu: Tutti

Questo non significa che il modulo sarà visibile su tutte le pagine perché la posizione tabs che abbiamo aggiunto non è richiamata nel codice del template. Caricheremo il contenuto del modulo da codice (vedremo subito come).

Ripetere le stesse identiche operazioni per il modulo mod_mostread (Articoli più letti). Potete ovviamente scegliere due (o più) moduli diversi.

Creare un file tabs_moduli.php con questo contenuto

<?php
JHTML::stylesheet('tabs.css','jumi_includes/');
jimport('joomla.html.pane');
$tabs = &JPane::getInstance('tabs');
echo $tabs->startPane('moduli-tabs');

$document = &JFactory::getDocument();
$renderer = $document->loadRenderer('module');

La prima parte è identica al primo esempio. Le ultime due righe servono ad ottenere un'istanza dell'oggetto renderer per la visualizzazione del contenuto dei moduli. Non mi dilungo in troppi dettagli.

$i = 1;
foreach (JModuleHelper::getModules('tabs') as $mod)  {

Per ogni modulo assegnato alla posizione tabs

 echo $tabs->startPanel($mod->title, 'mod'.$i);

si crea un tab che ha per titolo il titolo del modulo

 echo $renderer->render($mod);
 echo $tabs->endPanel();

come contenuto del tab si inserisce il contenuto del modulo ottenuto utilizzando l'oggetto renderer e si chiude il tab

 $i++;
}
echo $tabs->endPane();
?>

Effettuare l'upload di tabs_moduli.php nella cartella jumi_includes usata in precedenza.

Creare un articolo, ma va bene anche quello creato in precedenza, e inserire nel contenuto il comando Jumi

{jumi [jumi_includes/tabs_moduli.php]}

Salvare e visualizzare l'articolo nel frontend. Il risultato dovrebbe essere di questo tipo

Mi sembra una buona soluzione salva spazio: si possono pubblicare più moduli nello spazio occupato da uno e lasciare che sia l'utente a scegliersi le informazioni da visualizzare selezionando le tabs.

Oltre al plugin esiste un modulo Jumi. Negli esempi abbiamo sempre utilizzato le tabs nel contenuto di un articolo, con il modulo Jumi possiamo utilizzarle allo stesso modo in una posizione modulo del template.

Per modificare l'aspetto e i colori delle tabs ed adattarli al template è necessario agire sul file tabs.css.

Questo è un post da smanettoni. Può darsi, sinceramente non mi sono messo a spulciare la directory delle estensioni su joomla.org, che ci siano moduli già pronti che fanno questo genere di cose. Però scriversi il codice a mano ci ha consentito di conoscere alcune funzioni del framework che possono sempre tornare utili.

Alla prossima.

martedì 10 giugno 2008

Mootools. Funzione initialize e options

Continuiamo lo sviluppo della classe QScroller. Partiamo dal codice includendo questa volta le istruzioni per la creazione di un'istanza scroller.

var QScroller = new Class({
  options: { (1)
    slides: 'qslide',
    direction: 'h',
    duration: 3000,
    auto: false,
    delay: 1000,
    transition: Fx.Transitions.linear
  },
  initialize: function(wrapper,options) { (2)
    this.setOptions(options); (5)
    /* ... */
  },
  /* ... */
});
QScroller.implement(new Options, new Events);

var opt = { (4)
  auto:true,
  onMouseEnter: function(){this.stop();},
  onMouseLeave: function(){this.play();}
}
var scroller = new QScroller('qscroller1',opt); (3)

(1) options è una proprietà standard, come si vede è un oggetto le cui proprietà sono inizializzate con valori predefiniti. Ne vedremo tra poco l'utilizzo.
(2) se una classe possiede una funzione initialize() questa sarà eseguita ogni volta che un'istanza viene creata e riceverà gli argomenti che abbiamo passato al costruttore.
(3) In questo esempio passiamo al costruttore 2 argomenti.
(4) Per il momento concentriamoci sul secondo, l'oggetto opt.
(5) Questo oggetto viene utilizzato in initialize() dalla funzione setOptions() (che la nostra classe eredita da Options per effetto di implement):

  • quando è definita una proprietà in opt presente anche nell'oggetto options di cui al punto (1), il valore in opt sovrascrive quello in options.
  • quando è definita una proprietà in opt non presente nell'oggetto options, la proprietà in opt viene aggiunta ad options.
  • le proprietà in options non definite in opt mantengono ovviamente il valore preimpostato.

Detto questo dopo l'esecuzione del codice sopra riportato i valori della proprietà options di scroller saranno i seguenti

scroller.options.slides -> 'qslide'
scroller.options.direction -> 'h'
scroller.options.duration -> 3000
scroller.options.auto -> true
scroller.options.delay -> 1000
scroller.options.transition -> Fx.Transitions.linear
scroller.options.onMouseEnter -> function(){this.stop();}
scroller.options.onMouseLeave -> function(){this.play();}

A cosa servono tutte queste opzioni ancora non si è visto!

Penso che l'utilità di questo meccanismo fornito da Options e setOptions() sia chiara: predefinendo i valori di una serie di opzioni possiamo in molti casi ridurre il numero di argomenti da passare al costruttore, semplificando così l'utilizzo della classe.

Anche questo è un post breve. Continueremo l'esame della funzione initialize() la prossima volta.

venerdì 6 giugno 2008

Mootools. Struttura di una classe

Di Mootools ho già avuto modo parlare, ma essendomi divertito abbastanza con questo framework ultimamente, mi è venuta voglia di approfondire il discorso.

Come al solito, per evitare noiose spiegazioni teoriche partiremo da un esempio concreto e mostreremo (più o meno) passo passo come si crea una (più o meno) semplice classe Mootools.

Prima di proseguire è ben ricordare che le classi Mootools sono molto diverse concettualmente dalle classi a cui siamo abituati in altri linguaggi di programmazione orientati agli oggetti. Una classe Mootools è essa stessa un oggetto (cosa che risulta palese dal semplice fatto che si usa l'istruzione new per crearla), un oggetto che viene utilizzato come prototipo per la creazione di altri oggetti.

Detto questo, da ora in poi parlerò tranquillamente di classi ed istanze nella stessa accezione che questi termini hanno in linguaggi quali C++ o Java. Trattandosi di Javascript, la terminologia non sarà del tutto corretta, ma sarà più facile capirsi.

Anche se si tratta di un esempio, è opportuno cercare di sviluppare qualcosa che abbia una utilità pratica: la classe servirà a presentare sul nostro sito delle informazioni (testo ed eventualmente immagini) con un effetto di scorrimento orizzontale o verticale. Si vedrà come con Mootools sia possibile ottenere degli effetti gradevoli scrivendo relativamente poco codice.

Vediamo innanzi tutto la struttura della classe (i puntini di sospensione racchiusi tra commenti servono da segnaposto per il codice che dovrà essere scritto in seguito)

var QScroller = new Class({
  options: {/* ... */},
  initialize: function(wrapper,options) {
    /* ... */
  },
  load: function() {
    /* ... */
  },
  show: function() {
    /* ... */
  },
  doEffect: function() {
    /* ... */
  },
  stop: function(){
    /* ... */
  },
  play: function() {
    /* ... */
  },
  next: function() {
    /* ... */
  },
  prev: function() {
    /* ... */
  },
  swapSlides: function() {
    /* ... */
  }
});
QScroller.implement(new Options, new Events);

Sono molte righe, ma in realtà si tratta solo di due istruzioni!

Cercare di spiegare esattamente cosa succede a livello di framework sarebbe troppo complesso, accontentiamoci del risultato finale. Una volta eseguito il blocco di codice riportato sopra abbiamo a disposizione una classe QScroller. Le istanze di QScroller possiederanno le proprietà e i metodi definiti nell'oggetto (un oggetto letterale, notate le graffe) che passiamo come argomento alla funzione Class.

Con implement aggiungiamo a QScroller le funzionalità delle classi Options ed Events definite nel framework. In altre parole tutte le proprietà e i metodi di Options ed Events saranno copiati in QScroller che potrà utilizzarli come propri. Cosa questo comporti si vedrà in seguito.

A questo punto tutto quello che abbiamo è uno scheletro vuoto. La prossima volta inizieremo a scrivere il codice dei metodi a partire dalla importante funzione initialize().

L'argomento richiederà alcune 'puntate'. Aggiungo un'etichetta Mootools per dare modo a chi arrivi a metà del discorso di recuperare facilmente tutti gli articoli.

domenica 1 giugno 2008

Joomla 1.5: Inserire HTML, Javascript o PHP in un articolo

Tutti coloro che hanno avuto la necessità di inserire codice HTML o Javascript in contenuti Joomla! si saranno resi conto di quanto effettuare questa operazione con un editor WYSIWYG sia difficoltoso o quantomeno scomodo.

Ogni editor ha un funzione per visualizzare e modificare direttamente il sorgente html del contenuto e questo sembrerebbe risolvere il problema, ma non è così: infatti se utilizziamo questa funzione per inserire codice html o Javascript, al momento di salvare il contenuto ci accorgeremo che parte (molto spesso gran parte) del codice che abbiamo inserito è stato rimosso.

Questo accade perché di solito gli editor sono configurati per accettare solo un insieme limitato di tag html, e rimuovere automaticamente tutti gli altri. Questa non deve considerarsi una limitazione quanto piuttosto una misura di sicurezza importante soprattutto per i siti che consentono l'inserimento di contenuti da parte dei visitatori e che devono cautelarsi contro l'inserimento di codice o script potenzialmente pericolosi.

Detto questo resta il problema.

Una possibile soluzione consiste nel disabilitare l'editor WYSIWYG. In questo modo possiamo inserire html e Javascript nel contenuto senza alcun tipo di filtro e, terminata l'operazione e salvato il contenuto, riabilitare l'editor WYSIWYG. Questa soluzione non è ideale: infatti se a distanza di tempo abbiamo bisogno di apportare modifiche al contenuto è facile dimenticarsi che questo contiene codice inserito direttamente ed effettuare le modifiche con l'editor WYSIWYG abilitato. In questo modo al momento del salvataggio i filtri 'mutileranno' il codice inserito in precedenza con le conseguenze che è facile immaginare.

Un'altra possibilità è l'utilizzo di apposite estensioni di terze parti. Ce ne sono diverse, a mio parere, una delle migliori per questo tipo di situazioni è Jumi.

Il funzionamento di Jumi è semplicissimo: per prima cosa inseriremo il codice html e/o Javascript che si desidera in un file e ne faremo l'upload sul nostro sito (meglio se in un cartella apposita).

Poi utilizzeremo un semplice comando plugin per passare a Jumi il percorso del file che sarà incorporato nel nostro contenuto.

Esempio di utilizzo di Jumi

Installate Jumi come qualsiasi plugin Joomla! Attivatelo da Gestore plugin. Create poi un semplice file di testo salve.html con questo contenuto

<p>Salve da <b>Jumi</b></p>
<script type="text/javascript">
<!--
document.write('Un saluto a tutti!');
//-->
</script>

Via FTP create una cartella jumi_includes all'interno della stessa cartella dove è installato Joomla! e inseritevi il file salve.html

Create un nuovo articolo e inserite nel contenuto questo comando

{jumi [jumi_includes/salve.html]}

Salvate, pubblicate l'articolo e visualizzatelo nel frontend (non con la funzione anteprima articolo presente nel backend). Vedrete che il codice html e lo script sono stati inclusi nel contenuto. Lo script ovviamente è stato eseguito dal browser e quindi è visibile l'output dell'istruzione document.write()

Il percorso del file da includere da passare a Jumi è sempre relativo alla cartella in cui è installato Joomla! a meno che non si specifichi un diverso percorso di base nella configurazione del plugin.

Includere codice PHP in un articolo

E se volessimo includere codice PHP in un articolo? Gli script PHP, come si sa, non sono eseguiti nel browser, ma dal server per cui il metodo che abbiamo visto all'inizio, cioè l'inclusione diretta nel contenuto previa disabilitazione dell'editor WYSIWYG, non funziona.

Anche in questa situazione Jumi ci viene in aiuto. Create con un normale editor di testo un file di nome salve.php con questo contenuto (un classico)

<?php
echo 'Salve Mondo!';
?>

Inseritelo via FTP nella stessa cartella utilizzata in precedenza jumi_includes. A questo punto il comando da inserire nell'articolo è semplicemente

{jumi [jumi_includes/salve.php]}

Salvate e visualizzate l'articolo come in precedenza: la scritta di saluto apparirà nel vostro contenuto nella posizione dove avete inserito la stringa di comando.

Oltre al plugin, esiste anche un modulo Jumi che vi consente di inserire html, javascript, php in una qualsiasi posizione modulo del vostro template.

Sul sito dello sviluppatore trovate maggiori dettagli ed esempi.