bloggers bloggers

Marco Napolitano
Messaggi: 78
Stelle: 0
Data: 12/06/20
Jader Jed Francia
Messaggi: 58
Stelle: 0
Data: 16/11/19
Paolo Gambetti
Messaggi: 2
Stelle: 0
Data: 11/11/19
Katia Pazzi
Messaggi: 1
Stelle: 0
Data: 27/06/19
Ezio Lombardi
Messaggi: 11
Stelle: 0
Data: 10/04/18
Chiara Mambretti
Messaggi: 25
Stelle: 0
Data: 27/02/17
Serena Traversi
Messaggi: 3
Stelle: 0
Data: 21/07/16
Francesco Falanga
Messaggi: 8
Stelle: 0
Data: 14/06/16
Antonio Musarra
Messaggi: 2
Stelle: 0
Data: 18/11/13
Simone Celli Marchi
Messaggi: 6
Stelle: 0
Data: 09/07/13
Indietro

Trasferire informazioni da IFrame a container

Oggi vi parlerò di IFrame e di Javascript per un problema che ho avuto utilizzando Liferay ma che in realtà può essere applicato anche in altri contesti.

La necessità che avevo era quella di visualizzare una pagina di Liferay 7.2 all'interno di un IFrame di una pagina di Liferay 6.2; inoltre avevo bisogno che l'IFrame si ridimensionasse in altezza automaticamente in modo da evitare il classico problema della doppia barra di scorrimento laterale.

I più attenti di voi potrebbero dire: "Liferay ha già una portlet IFrame che fa esattamente quello che ti serve". Vero, peccato però che il ridimensionamento dell'IFrame non funzioni perchè vengono messi in atto dei controlli di sicurezza per cui Javascript non è in grado di recuperare dall'IFrame le informazioni necessarie per determinarne l'altezza; e nemmeno l'IFrame è in grado di invocare funzioni Javascript sul container esterno, per lo stesso motivo.

Inoltre Liferay non consente che le sue pagine siano incluse in un IFrame (la famigerata Same Origin policy), quindi di problemi da risolvere ce ne sono diversi; ma procediamo per passi.

Il primo problema che risolviamo è fare in modo che le pagine di Liferay 7.2 possano essere incluse in un IFrame; per questo dobbiamo creare il file system-ext.properties e posizionarlo nella cartella <tomcat>/webapps/ROOT/WEB-INF/classes. Il contenuto del file sarà l'elenco numerale di tutte le URL che devono essere incluse nell'IFrame, come ad esempio:

http.header.secure.x.frame.options.0=/pagina-1
http.header.secure.x.frame.options.1=/web/guest/pagina-1
http.header.secure.x.frame.options.2=/en/page-1
http.header.secure.x.frame.options.3=/en/web/guest/page-2
http.header.secure.x.frame.options.4=...
http.header.secure.x.frame.options.5=...

A questo punto possiamo salvare il file, riavviare il server di Liferay 7.2 e finalmente riusciremo ad includere le specifiche pagine in un IFrame su Liferay 6.2.

Bene, ma ora come facciamo a ridimensionare automaticamente l'IFrame in altezza? Per ottenere il risultato voluto dobbiamo riuscire a trasferire informazioni dall'IFrame al container. Per fare ciò dobbiamo scomodare Javascript ed in particolare la funzione postMessage che consente di inviare "messaggi" da una finestra ad un'altra del browser (anche non IFrame). Non entro nei dettagli della funzione ma se siete curiosi leggete qui.

A questo punto, nella JSP della portlet da includere nell'IFrame aggiungiamo questo frammento di codice:

<aui:script use="aui-base">
var content = A.one('#content');
var height = content.height();

parent.postMessage('{"height": ' + height + '}', '*');
</aui:script>

Il codice non fa altro che recuperare l'elemento del DOM che rappresenta il contenuto della pagina e calcolarne l'altezza in pixel; dopodichè invia alla finestra parent (ossia il container dell'IFrame) un messaggio. Nel caso specifico il messaggio è una stringa che rappresenta un oggetto JSON con tutte le informazioni necessarie, nel nostro caso l'altezza in pixel; fate attenzione perchè la funzione postMessage consente di inviare anche oggetti ma, se non ricordo male, il buon vecchio IE supporta invece solamente stringhe.

Ora possiamo spostarci su Liferay 6.2 dove dobbiamo andare ad intercettare il messaggio inviato dall'IFrame; il dove è ovviamente la JSP che visualizza l'IFrame e quindi avete 2 possibilità (nessuna delle quali verrà analizzata in questo post perché immagino siate già in grado di farlo da soli):

  1. fare un hook sulla portlet IFrame di Liferay 6.2
  2. farvi una vostra portlet custom per includere l'IFrame

Quello che interessa a me adesso è solamente farvi vedere il codice per intercettare il messaggio:

<aui:script use="aui-base">
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
var listener = window[eventMethod];

// Ascolta i messaggi che arrivano dall'altra finestra
listener(messageEvent, function(e) {
    var key = e.message ? "message" : "data";
    // Contenuto del messaggio
    var data = e[key];

    try {
        // Sapendo che il messaggio è in formato JSON, lo convertiamo
        var json = A.JSON.parse(data);
        
        // Recupero del nodo del DOM che rappresenta l'IFrame
        var iframe = A.one('#<portlet:namespace />iframe');

        // Se il nodo esiste, ne imposto l'altezza
        if (iframe)
            iframe.setStyle('height', json.height);
    } catch(e) {
        console.error(e);
    }
}, false);
</aui:script>

Forte vero? Chiaramente vi ho fatto vedere solamente come modificare l'altezza ma nel messaggio potete inviare qualunque informazione e farne poi quello che volete.

Successivo
Commenti
Nessun commento. Vuoi essere il primo.