mercoledì 31 ottobre 2007

Joomla 1.0: Funzione di Configurazione di un Componente

Tutti i componenti per Joomla, a meno che si tratti di componenti estremamente semplici, offrono all'utilizzatore la possibilità di impostare un certo numero di parametri di configurazione e preferenze.

La gestione di questa funzionalità viene fatta dall'area di amministrazione componenti di Joomla (backend).

Ho scritto un micro componente per mostrare uno dei tanti modi in cui questo tipo di funzionalità può essere implementata. L'occasione è stata la risposta ad una domanda fatta nel forum italiano a www.joomla.org.

Il componente utilizza ConfigMagik una classe open source trovata su phpclasses.org che serve a leggere e scrivere file in formato INI standard (quello usato da php.ini per intendersi).

Esempio di file di configurazione

[sezione1]
parametro1 = "valore1"
parametro2 = "valore2"
[sezione2]
parametro1 = "valore1"
parametro2 = "valore2"

L'uso della classe è semplice. Si crea un'istanza in questo modo

$Cfg = new ConfigMagik('ini_path');

ini_path contiene il percorso completo al file di configurazione che viene caricato immediatamente, ovviamente se esiste, dal costruttore della classe.

Per leggere il valore di un parametro dal file di configurazione si utilizza il metodo get passando come argomenti gli identificativi del parametro e della sezione. I parametri possono infatti essere ordinati in sezioni il che consente di utilizzare lo stesso identificativo per parametri diversi purché appartenenti a sezioni diverse.

Usando come esempio il file di configurazione riportato sopra si avrebbe

$valore1 = $Cfg->get('parametro1', 'sezione1');

Per modificare il valore di un parametro si utilizza il metodo set

$Cfg->set('valore1', $nuovo_valore1, 'sezione1');

Se si imposta a true il parametro synchronize quando si crea l'oggetto di classe ConfigMagik il file di configurazione è immediatamente aggiornato con il nuovo valore del parametro impostato con il metodo set.

Altrimenti (synchronize uguale a false) il nuovo valore del parametro è salvato internamente alla classe e bisogna invocare il metodo save per aggiornare il file di configurazione.

$Cfg->save();

Rimando per ulteriori dettagli al sorgente della classe che è ben documentato.

Il componente di esempio è scheletrico, ma completo. Può essere scaricato dal sito (cconfig.zip) e installato. Dall'area di amministrazione (menu Configurazione) si potranno inserire due valori nel file di configurazione. Creando un link al componente (o inserendo direttamente nel browser la url .../index.php?option=com_cconfig) i valori saranno visualizzati su schermo.

martedì 23 ottobre 2007

Textpattern: Liste Articoli e Pagine Statiche

Proseguiamo la creazione del sito di esempio con Textpattern. Invece di continuare ad apportare le modifiche sullo stesso sito creato nel corso del primo articolo, ho preferito farne una copia (questa) in modo che, arrivati alla fine, sia possibile un confronto del tipo "prima e dopo la cura".

Chi avesse creato passo passo la propria versione del sito leggendo l'articolo precedente, può semplicemente riprendere il filo e continuare a lavorare su quello.

Come prima cosa ho inserito un altro articolo come riempitivo sia perché un solo articolo non basta per dimostrare certe funzioni, sia per avere l'occasione di scrivere qualche altra fesseria.

Poi ho scritto un sommario (excerpt se avete la versione inglese) per ogni articolo della sezione PHP.

Il sommario si inserisce in una casella di testo etichettata sommario (eh gia!) che si trova sotto l'area di inserimento articolo (Contenuti -> Scrivi oppure Contenuti -> Articoli e click sul titolo dell'articolo).

E' forse inutile precisare, ma lo faccio lo stesso, che il sommario non deve necessariamente essere presente, può essere inserito quando si scrive l'articolo o modificando l'articolo successivamente, può contenere tag html e può essere scritto con la sintassi Textile esattamente come il contenuto principale dell'articolo.

Liste articoli con sommario

Tutto questo lavoro preparatorio serve alla prima modifica da apportare al sito: vogliamo che in prima pagina e nella sezione Articoli sia presentato soltanto il sommario degli articoli più recenti con un link (leggi tutto ...) che porti alla versione completa dell'articolo visualizzata a tutta pagina.

Per ottenere questo è necessario modificare il modulo articolo default (Aspetto -> Moduli) in questo modo

<h3>
  <txp:permlink>
    <txp:title />
  </txp:permlink> 
  &#183; <txp:posted />
</h3>
<txp:if_article_list>
  <txp:excerpt />
  <txp:permlink>Leggi tutto ...</txp:permlink>
<txp:else />
  <txp:article_image class="article-image" />
  <txp:body />
  <p>&#8212; <txp:author /></p>
  <txp:comments_invite wraptag="p" />
</txp:if_article_list>
<div class="divider">
  <img src="<txp:site_url />images/1.gif" width="400" 
  height="1" alt="---" title="" />
</div>

Le righe in blu sono quelle da aggiungere le altre dovreste averle ereditate dalle modifiche fatte negli articoli precedenti.

L'uso di Textpattern, una volta appresi i concetti base, è molto più intuitivo di quello che potrebbe sembrare a prima vista. I nomi dei tag sono descrittivi, per cui basta leggere (e tradurre) per capire il senso delle modifiche appena fatte.

<txp:if_article_list> è un tag condizionale, serve ad includere certi tag se una certa condizione è vera ed altri tag se la stessa condizione è falsa. La condizione in questo specifico caso è la visualizzazione di una lista di articoli.

Quindi stiamo dando a Textpattern queste istruzioni.

Se il modulo articolo default è utilizzato per la visualizzazione di una lista di articoli (<txp:if_article_list>), mostra il sommario (<txp:excerpt />) seguito da un link alla pagina individuale dell'articolo (<txp:permlink>) usando Leggi tutto ... come testo cliccabile del link. In ogni altro caso (<txp:else />), quindi quando l'articolo è visualizzato non in una lista ma individualmente, mostra una eventuale immagine associata all'articolo (<txp:article_image class="article-image" />), il corpo completo (<txp:body />), l'autore (<txp:author />) e l'invito a commentare (<txp:comments_invite />).

Se visualizzate il sito dopo aver fatto queste modifiche al modulo vedrete che in prima pagina e nella sezione Articoli viene mostrato solo il sommario degli articoli e il link Leggi tutto ....

Pagine statiche

Il problema è che la stessa cosa succede anche nella sezione Chi Siamo e questo non va bene. Questa sezione infatti contiene (e sempre conterrà) un solo articolo per cui non ha senso costringere il visitatore a cliccare un link Leggi tutto. L'articolo dovrà essere mostrato per esteso non appena si entra nella sezione.

In pratica vogliamo dare alla sezione Chi Siamo l'apparenza di una pagina statica. Questo è possibile creando un nuovo modello di pagina da assegnare alla sezione. Fino ad ora infatti abbiamo usato il modello pagina default per tutte le sezioni.

Prima di procedere è necessario un po' di lavoro preliminare. Nel momento in cui si devono utilizzare più modelli pagina per un unico sito è necessario che la struttura dei singoli modelli sia il più modulare possibile in modo da evitare duplicazioni di codice e rendere più semplice apportare future modifiche.

Questa è la struttura attuale della pagina default

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" 
lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; 
  charset=utf-8" />
  <title><txp:page_title /></title>
  <txp:feed_link flavor="atom" format="link" label="Atom" />
  <txp:feed_link flavor="rss" format="link" label="RSS" />
  <txp:css format="link" />
</head>
<body>

<!-- accessibility -->
<div id="accessibility">
  <ul>
    <li>
      <a href="#content">
        <txp:text item="go_content" />
      </a>
    </li>
    <li>
      <a href="#sidebar-1">
        <txp:text item="go_nav" />
      </a>
    </li>
    <li>
      <a href="#sidebar-2">
        <txp:text item="go_search" />
      </a>
    </li>
  </ul>
</div>

<div id="container">
  <!-- head -->
  <div id="head">
    <h1><txp:link_to_home><txp:site_name /></txp:link_to_home></h1>
    <h2><txp:site_slogan /></h2>
  </div>

  <!-- left -->
  <div id="sidebar-1">
    <txp:section_list break="li" wraptag="ul" />
    <txp:linklist wraptag="p" />
  </div>

  <!-- right -->
  <div id="sidebar-2">
    <txp:search_input wraptag="p" />
    <txp:popup type="c" wraptag="p" />
    <p>
      <txp:feed_link label="RSS" /> / 
      <txp:feed_link flavor="atom" label="Atom" />
    </p>
  </div>

  <!-- center -->
  <div id="content">
    <txp:article limit="5" />
    <txp:if_individual_article>
      <p>
        <txp:link_to_prev>
          <txp:prev_title />
        </txp:link_to_prev> 
        <txp:link_to_next>
          <txp:next_title />
        </txp:link_to_next>
      </p>
    <txp:else />
      <p>
        <txp:older>
          <txp:text item="older" />
        </txp:older> 
        <txp:newer>
          <txp:text item="newer" />
        </txp:newer>
      </p>
    </txp:if_individual_article>
  </div>

  <!-- footer -->
  <div id="foot">&nbsp;</div>
</div> <!-- end container -->
</body>
</html>

Inseriamo in moduli separati le parti che possono essere comuni a più pagine.

Creiamo un nuovo modulo. Aspetto -> Moduli e link Crea un nuovo modulo sulla colonna di destra.

Impostiamo head come nome modulo e misc come tipologia, il contenuto del modulo è il seguente.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" 
lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; 
  charset=utf-8" />
  <title><txp:page_title /></title>
  <txp:feed_link flavor="atom" format="link" label="Atom" />
  <txp:feed_link flavor="rss" format="link" label="RSS" />
  <txp:css format="link" />
</head>

Salviamo e ripetiamo essattamente la stessa procedura per creare un modulo accessibility (sempre tipologia misc come tutti gli altri creati di seguito) con il seguente contenuto

<div id="accessibility">
  <ul>
    <li>
      <a href="#content">
        <txp:text item="go_content" />
      </a>
    </li>
    <li>
      <a href="#sidebar-1">
        <txp:text item="go_nav" />
      </a>
    </li>
    <li>
      <a href="#sidebar-2">
        <txp:text item="go_search" />
      </a>
    </li>
  </ul>
</div>

Modulo header

<h1>
  <txp:link_to_home><txp:site_name /></txp:link_to_home>
</h1>
<h2>
  <txp:site_slogan />
</h2>

Modulo navbar

<txp:section_list break="li" wraptag="ul" />
<txp:linklist wraptag="p" />

Modulo rightcol

<txp:search_input wraptag="p" />
<txp:popup type="c" wraptag="p" />
<p>
  <txp:feed_link label="RSS" /> / 
  <txp:feed_link flavor="atom" label="Atom" />
</p>

Modulo bottomnav

<txp:if_individual_article>
  <p>
    <txp:link_to_prev>
      <txp:prev_title />
    </txp:link_to_prev> 
    <txp:link_to_next>
      <txp:next_title />
    </txp:link_to_next>
  </p>
<txp:else />
  <p>
    <txp:older>
      <txp:text item="older" />
    </txp:older> 
    <txp:newer>
      <txp:text item="newer" />
    </txp:newer>
  </p>
</txp:if_individual_article>

Modulo footer

<div id="foot">&nbsp;</div>
</div> <!-- end container -->
</body>
</html>

Il modello pagina default può essere riscritto utilizzando i moduli appena creati.

<txp:output_form form="head" />
<body>
<txp:output_form form="accessibility" />
<div id="container">
  <div id="head">
    <txp:output_form form="header" />
  </div>
  <div id="sidebar-1">
    <txp:output_form form="navbar" />
  </div>
  <div id="sidebar-2">
    <txp:output_form form="rightcol" /> 
  </div>
  <div id="content">
    <txp:article limit="5" />
    <txp:output_form form="bottomnav" />
  </div>
<txp:output_form form="footer" />

Non è difficle intuire che il tag <txp:output_form /> serve ad includere il contenuto di un modulo il cui nome viene indicato nell'attributo form.

Possiamo a questo punto creare il modulo articolo da utilizzare sulla pagina statica. Come al solito Aspetto -> Moduli, Crea un nuovo modulo.

Nome static_art, tipologia modulo article

<h3><txp:title /></h3>
<txp:article_image class="article-image" />
<txp:body/>

Non visualizziamo nè autore, nè data perché non avrebbero senso per questo tipo di articolo.

A questo punto possiamo creare il modello della pagina statica.

Aspetto -> Pagine e selezioniamo default (dovrebbe essere già selezionata). Nel campo Copia pagina come: (sotto l'area di testo che contiene la definizione del modello) inseriamo static e premiamo il pulsante Copia.

Viene creata una copia della pagina default con il nome static. Dobbiamo fare una sola modifica. Trovato il tag

<txp:article limit="5" />
Lo sostituiamo con
<txp:article form="static_art" />

Poiché usiamo un modulo articolo diverso da default ne dobbiamo indicare il nome nell'attributo form del tag <txp:article />. Salviamo la pagina static. Resta solo da assegnare il modello appena creato alla sezione Chi Siamo

Aspetto -> Sezioni, nell'elenco modifichiamo il campo Usa la pagina della sezione chi-siamo da default a static.

Abbiamo finito. La prima pagina e la sezione Articoli mostrano adesso una lista di articoli con sommario e link Leggi tutto, la sezione Chi Siamo contiene un singolo articolo mostrato per intero.

Per concludere

Tutte le modifiche sono incluse nella versione aggiornata del sito di esempio. Per riassumere
  • Abbiamo modificato il modulo articolo default per ottenere un formato di visualizzazione diverso a seconda che l'articolo sia visualizzato all'interno di una lista articoli o in una pagina individuale.
  • Abbiamo creato una serie di moduli di tipo misc contenenti codice da usare su più modelli pagina e utilizzato questi moduli per semplificare la struttura della pagina default
  • Abbiamo creato un nuovo modulo articolo static_art da utilizzare in una pagina statica.
  • Abbiamo creato il modello di pagina static e lo abbiamo assegnato alla sezione Chi Siamo
Alla prossima.

mercoledì 3 ottobre 2007

Aggiornamento Menu Javascript (QMenu)

Mi è stato fatto notare che QMenu, il menu a tendina in Javascript presentato in questo articolo, presenta dei problemi quando viene usato in una pagina che non contiene un DOCTYPE valido visualizzata da Internet Explorer.

Questo succede perché Internet Explorer utilizza il cosiddetto quirks mode per visualizzare un documento html/xhtml privo di DOCTYPE. Le conseguenze, per quello che interessa il nostro script e senza voler approfondire più di tanto, sono che i tag DIV che compongono gli elementi del menu sono dimensionati e posizionati in modo leggermente diverso rispetto a quanto avviene negli altri browser (e nello stesso Internet Explorer in standard mode, cioè in presenza di un DOCTYPE valido nel documento).

Tutto questo causa degli antiestetici spazi vuoti tra i vari elementi del menu.

La soluzione sarebbe quella di utilizzare sempre un DOCTYPE valido per i propri documenti html/xhtml ed evitare del tutto le problematiche relative al quirks mode. Però è vero che ci sono siti web che, per ignoranza del web designer o perché molto vecchi, sono stati creati assumendo che il quirks mode fosse l'unica modalità di visualizzazione.

In questi casi casi aggiungere un DOCTYPE e forzare lo standard mode può produrre errori di visualizzazione delle pagine in Internet Explorer.

L'unica possibilità è quindi quella di modificare lo script in modo che si adatti alle diverse modalità di visualizzazione. Ed è quello che ho fatto anche perché se no questa lunga introduzione servirebbe a ben poco.

Individuare il 'quirks mode' in Javascript

Per individuare se il documento viene visualizzato dal browser in quirks mode si usa la proprietà compatMode dell'oggetto document in questo modo

if(document.compatMode=='BackCompat') {
 //siamo in quirks mode
}

Cosa faccia lo script in questa situazione lo lascio scoprire, chiaramente a chi interessa, controllando il sorgente. Non è niente di difficile, solo semplici aggiustamenti per correggere la posizione degli elementi del menu quando la modalità di visualizzazione è quirks mode e il browser è Internet Explorer.

La versione modificata (1.01) di QMenu è scaricabile dal sito.

Ho cercato di provare bene la modifica su tutte le versioni dei browser su cui ho potuto mettere le mani, fatemi sapere se incontrate problemi.