Joomla, editing delle informazioni in finestra modale
Le finestre modali sono tanto amate dagli utenti quanto odiate dai programmatori puristi che non gradiscono proprio vedere i flussi del programma mischiarsi ed intrecciarsi secondo gli schemi della per fortuna dimenticata programmazione a goto.
In questa trattazione ci occuperemo della programmazione lato back end e supporremo di avere un componente strutturato secondo i dettami di programmazione di joomla 2.5+, ma i concetti qui espressi si applicano anche ai componenti che prevedano la possibilità di editare le informazioni lato front end.
Avete bisogno di aiuto per sviluppare componenti particolari? Non esitate a contattarci, svilupperemo per voi le estensioni per mettere in produzione le vostre idee: è uno dei nostri servizi.
Le finestre modali in Joomla
La buona notizia è che joomla comunque prevede già il codice js per gestire le finestre modali, basta attribuire al link la classe "modal" e la libreria mootools provvederà a gestire la finestra SqueezeBox. La libreria prevede due modalità di gestione della finestra:
- all'interno di un div tramite ajax;
- all'interno di un iframe tramite il normale flusso dell'html.
Ciascun metodo ha i suoi pro ed i suoi contro, vediamo di analizzarli nel seguito di questo articolo.
Una doverosa premessa è che, per l'editing o comunque la visualizzazione di una determinata informazione in finestra modale, non avremo bisogno della cornice di contorno di joomla con bottoni e menù, pertanto tutti i link destinati ad aprire le suddette finestre dovranno riportare nella query string l'informazione 'tmpl=component' in modo da limitare l'output di joomla al solo codice generato dal componente in questione.
Questo è un articolo di livello tecnico abbastanza elevato ed è diretto a programmatori esperti. Molti dei concetti espressi in questa pagina richiedono una buona conoscenza del framework di Joomla per essere compresi.
Finestra modale in ajax
In questo caso la pagina puntata dal link è caricata direttamente all'interno di quella che contiene il link stesso; ne consegue che le azioni eseguite dal codice caricato, quali link e submit di form, hanno effetto sulla pagina stessa.
Si tenga presente un'altra peculiarità: sebbene joomla restituisca sempre una pagina html completa, il codice ajax conserva la sola parte body della pagina ricevuta. Ciò è facilmente capibile dato che il codice deve essere inserito in un tag div contenuto all'interno della pagina, ma ha un pericoloso effetto collaterale. La sezione head della pagina contiene infatti tutti i js necessari al funzionamento del codice di editing, e se questa viene rimossa nulla funzionerà più; pertanto, in questi casi, bisognerà avere l'accortezza di spostare il caricamento di detti js dalla pagina che sarà visualizzata nella finestra modale a quella che ospita il div modale.
considerate anche che SqueezeBox carica il div impostandone lo z-index del layer a valori superiori a quelli dei normali controlli modali, con il risultato che gli altri controlli modali, ad esempio il calendario, non sono più accessibili dato che vengono visualizzati al di sotto del layer cui si riferiscono!
Da quanto sopra consegue che la finestra modale in line div è, di norma, più indicata per la visualizzazione delle informazioni che non per l'editing delle stesse.
Finestra modale in iframe
Sul fronte opposto rispetto a quanto visto sopra, abbiamo il caricamento della finestra modale all'interno di un in line frame. L' iframe consente un assoluto isolamento tra le operazioni che avvengono nella finestra modale e la pagina che la contiene consentendo tutte le operazioni che non erano possibili nella precedente modalità, ma complicando un poco la comunicazione con la finestra contenitrice (parent, in javascript). Un esempio di ciò è il fatto che per l'iframe è necessario specificare una dimensione non potendo essere lo stesso auto adattivo.
Il vantaggio maggiore è che la pagina indicata nel link è caricata così nome restituita da Joomla, con tutta la sezione head e quindi con ogni javascript e css necessario al funzionamento della pagina medesima, inoltre essendo una pagina vera e propria, anche se all'interno di un pannello modale, i controlli modali usata in questa non sono in conflitto con lo z-index del parent, né in conflitto può esserci niente altro.
Da quanto sopra consegue che nella maggior parte dei casi per effettuare l'editing in modalità modale è sufficiente caricare la pagina di editing standard in un iframe.
Qualora si desideri aprire un link in una finestra modale iframe, oltre alla classe modal, è necessario specificare anche il tipo di handler richiesto tramite l'attributo rel, ad esempio si può aggiungere al link l'attributo rel="{handler:'iframe'}". Piccola nota: se non espressa esplicitamente viene assegnata una dimensione di default alla finestra dell'iframe.
Si, ma dove sono i pulsanti per salvare?
I pulsanti destinati a salvare il record, abbandonare le modifiche e così via, sono caricati al di fuori della area del componente, in quanto parte del framework di joomla, pertanto quando apriamo una pagina inserendo nella query string 'tmpl=component' i pulsanti non appaiono e dobbiamo provvedere noi a inserirli.
In coda al template per l'editing: inseriamo:
<input onclick="Joomla.submitbutton('nomecontroller.save');" type="button" value="<?php echo JText::_( 'JSAVE' ); ?>" /> <input onclick="Joomla.submitbutton('nomecontroller.cancel');" type="button" value="<?php echo JText::_( 'JCANCEL' ); ?>" />
Ed otterremo il pulsante per salvare e quello per chiudere la finestra. Su questi pulsanti torneremo dopo, per ora si noti che nome controller è il nome del file del controller preposto al singolo elemento.
Nel caso della semplice visualizzazione o dell'inserimento di un nuovo record, non avendo un record esistente in stato di editing e di lock, il pulsante per chiudere la finestra si riduce a:
<input onclick="parent.SqueezeBox.close();" type="button" value="<?php echo JText::_( 'JCANCEL' ); ?>" />
Visualizzazione ed editing di dati in finestra modale
Che si scelga la prima o la seconda modalità di visualizzazione dei dati, dobbiamo però fare una distinzione tra le operazioni predefinite del framework di joomla: view e save da una parte edit dall'altra.
Se è possibile visualizzare un record o crearne uno nuovo richiamando direttamente la view relativa, non è possibile modificare un record già presente richiamando la view di editing del medesimo. All'inizio dell'editing Joomla marca il record come in edit nello spazio user state ed effettua il redirect alla view di editing; all'atto del salvataggio Joomla controlla se è presente la marcatura per l'editing, altrimenti restituisce un errore e non procede.
Nessun problema finché non vogliamo passare dei parametri alle funzionalità di editing del record, ma se così è abbiamo un piccolo problema. Facciamo un esempio di parametro da passare: immaginiamo di voler usare una finestra modale ajax per l'editing: si è stato sconsigliato, ma noi non seguiamo i consigli.
Il sistema ajax, usato per popolare il div in cui sarà effettuato l'editing, è in grado di di seguire la redirezione imposta dal controller (http status 303) e di caricare la view opportuna con il record corretto, ma la pressione del tasto di salvataggio, come detto, influenzerà tutta la pagina, all'interno della quale sarà caricato il controller del recordset del record modificato, non del chiamante.
Facciamo un esempio per chiarire il concetto. Gestiamo una biblioteca; all'interno del nostro componente avremo un controller (con relativi model e view, ma qui focalizziamoci sul controller) per l'editing dei singoli libri che si chiamerà book, avremo poi un controller per visualizzare l'elenco dei libri che, stando agli standard joomla, dovrà chiamarsi books (con la s finale per il plurale). Ipotizziamo ora che tra le proprietà di ciascun libro ci sia anche uno stato che indica se il libro è in visione o se è possibile prenderlo in prestito. Ora noi vogliamo poter modificare questa proprietà dalla pagina che gestisce le situazioni dei prestiti, pagina che si trova sotto il controller bookinghistorys (sì, lo so che non è un plurale corretto, ma è lo standard Joomla). All'interno della view del controller potremmo usare il seguente link:
<a href="'index.php?option=com_bookshop&tmpl=component&task=book.edit&id_book=<?php echo $id_book; ?>" class="modal" >Modifica libro</a>
Ci accorgeremmo subito che una volta effettuato l'editing ci apparirebbe la view collegata a books e non a bookinghistorys, perché? Semplice, perché di default Joomla ritorna alla lista dei record del tipo appena editato. A questo punto avrete tutti pensato che sia sufficiente inserire l'url cui effettuare il ritorno all'interno della query string, ma la cosa purtroppo non funziona proprio.
Passare parametri ad una finestra modale di editing
Poco sopra abbiamo detto che Joomla, quando riceve tramite il controller una richiesta di edit (book.edit) marca il record per l'editing ed effettua una redirezione alla view di editing. Il problema è proprio in questo ultimo passaggio: la redirezione non tiene assolutamente conto di quanto passato in url, salvo che per i parametri canonici di Joomla (quali layout e tmpl, per citare i meno ovvi), tutto il resto viene perso.
Come è allora possibile fare sì che un codice come il seguente funzioni?
<?php $link = 'index.php?option=com_bookshop&tmpl=component&task=book.edit&id_book=' .$id_book. '&return='. urlencode(base64_encode(JURI::getInstance()->toString(array('path','query')))); ?> <a href="'<?php echo $link; ?>" class="modal" >Modifica libro</a>
Dovremo intervenire sul controller (book.php) e provvedere a gestire il task edit per trattare i dati che non sono gestiti dal controller di default (JControllerForm). Pertanto scriviamo l'override del metodo edit:
function edit($key = null, $urlVar = null) { $ret=parent::edit($key, $urlVar); $jin=JFactory::getApplication()->input; if($jin->getWord('return')){ $jap=JFactory::getApplication(); $jap->setUserState('com_bookshop.edit.book.personalvars.return', $jin->get('return')); } return $ret; }
Ovviamente lasceremo tutta la gestione di default al framework di Joomla, e nel nostro override ci occuperemo solo di salvare i dati che ci interessano nello user state, notate solo l'aggiunta della chiave personalvars per non correre il rischio di collisioni con altre chiavi del sistema/componente. Noi abbiamo usato un solo valore da salvare, ma ovviamente è solo un esempio e se ne possono usare quanti se ne vuole.
Il controller ora effettuerà la redirezione alla view di editing, ma le variabili di nostro interesse sono ora salvate nello user state, dal quale potremo recuperarle per popolare la form di editing o semplicemente per trasferirle al passaggio successivo (save o cancel).
all'interno del codice dell view (view.html.php in book, nel nostro esempio) recuperiamo i dati salvati, per inserirli in un campo hidden da passare nuovamente al controller (task save):
<input type="hidden" name="return" value="<?php echo JFactory::getApplication()->getUserState('com_bookshop.edit.book.personalvars.return',''); ?>" />
Nel nostro caso abbiamo inserito il valore trasmesso direttamente all'interno del template di editing del record, come chiaramente capibile dalla sintassi.
L'ultimo passo che ora serve è quello di modificare i metodi save e cancel del controller book.php per gestire la pagina a cui tornare.
Vedremo solo il metodo save, dato che a parte il nome proprio e del parent non cambia niente:
function save($key = null, $urlVar = null) { $ret = parent::save($key, $urlVar); if($return=JFactory::getApplication()->input->get('return')){ JFactory::getApplication()->setUserState('com_bookshop.edit.book.personalvars', null); echo '<script type="text/javascript"> parent.location.href="' . base64_decode($return) . '";</script>'; exit(); } }
Per prima cosa lasciamo che il framework di Joomla compia tutte le operazioni necessarie per aggiornare il nostro record, poi azzeriamo le variabili che avevamo salvato nello user state ed infine inviamo al browser un javascript che effettui il redirect alla pagina da cui è partita l'operazione.
Nello specifico avremmo potuto usare, per la redirezione, sia le funzioni di redirect di joomla sia quelle di php, dato che lavoravamo in un div all'interno della pagina principale, il codice qui indicato funziona anche in caso di iframe.
Conclusioni
Certo questo articolo non è semplice, ma colma una delle lacune presenti nella documentazione più tecnica di Joomla. Avete bisogno di aiuto per sviluppare componenti particolari? Non esitate a contattarci.
Happy coding,
marco maria leoni
Please note: URL in text are not linked and user's site address is only for internal use and is not published.
Comments are human checked. All spam will be removed, so don't waste your time and, especially, mine!