Table of Contents

Programmazione con p.mapper 4

p.mapper 4 utilizza estensivamente la libreria jQuery ed alcune componenti del plugin UI per disegnare il proprio layout. Vedremo come utilizzare la versione completa del plugin UI per aggiungere del contenuto dinamico all'interfaccia di p.mapper.

Modificare il codice JavaScript

Il codice JavaScript di p.mapper è compresso e unito nell'unico file javascript/pm_cjs.js. Invece di modificare questo file è possibile prendere il file sorgente interessato (ad esempio javascript/src/pm.query.js) e farne una copia in config/common/ (viene caricato per ogni configurazione) oppure in config/default/ (viene caricato solo per la configurazione default).

Le modifiche alle funzioni JavaScript si effettuano in questo file e siccome questo file viene incluso dopo pm_cjs.js, le sue definizioni sovrascriveranno quelle predefinite.

Aggiungere un barra laterale

Modificare il layout dell'interfaccia, aggiungendo una barra laterale a sinistra. Si modifica il file map.phtml, nella sezione <head>:

    /**
     * Settings for jquery.ui.layout
     * ======= ADAPT TO PAGE LAYOUT =======
     */
    var myLayout;
 
    $(document).ready(function () {
        myLayout = $('body').layout({
        west__size: 200,
        north__size: 40,
        south__size: 35,
        east__size: 220,
        north__spacing_open: 0,
        south__spacing_open: 0,
        ...

Questa impostazione rende visibile il <div id="uiLayoutWest"> sul lato sinistro, largo 200 pixel. Il <div>, già presente nel file map.phtml originale, può quindi essere riempito con del contenuto.

Aggiungere del contenuto dinamico

jQuery UI accordion jQuery UI tabs

Per ottenere del contenuto dinamico (ad esempio dei tab oppure delle sezioni a scomparsa) possiamo sfruttare il plugin UI della libreria jQuery. Il plugin estende la libreria JavaScript jQuery e insieme ad un foglio di stile opportuno trasforma semplici blocchi <div> in oggetti attivi sulla pagina web.

La libreria jQuery è già inclusa in p.mapper, si tratta della versione 1.3.2 con una collezione minimale di plugin. Il tutto contenuto nel file javascript/jquery_merged.js.

Purtroppo il plugin UI non è nella sua versione completa, mancano ad esempio i widget Accordion e Tabs. Dopo aver scaricato dal sito l'archivio compresso, si scompatta il codice javascript e il foglio di stile, salvandoli rispettivamente nei file:

Per caricare un file .js o un file .css basta copiarlo nella directory config/common/, gli opportuni tag <script> e <link> vengono generati automaticamente.

Se si vuol un controllo maggiore sull'ordine in cui il codice JavaScript e i fogli di stile vengono caricati, si può aggiungere direttamente il codice HTML nel file map.phtml, nella sezione <head>.

<script type="text/javascript" src="config/common/jquery-ui-1.7.2.custom.min.js"></script>
<link rel="stylesheet" href="config/common/jquery-ui-1.7.2.custom.css" type="text/css" />

La <div id="uiLayoutWest"> deve essere riempita con normale codice HTML, secondo la documentazione del plugin UI. Il tutto è contenuto nel file map.phtml:

   <div class="ui-layout-west" id="uiLayoutWest">
        <!-- ===================== "Accordion" sections ===================== -->
        <div id="accordion">
            <h3><a href="#">Sezione 1</a></h3>
            <div>
                <p>Quel ramo del lago di Como, che volge a mezzogiorno, tra due catene non
                interrotte di monti, tutto a seni e a golfi, a seconda dello sporgere e
                del rientrare di quelli, vien quasi a un tratto, tra un promontorio a
                destra e un'ampia costiera dall'altra parte;
                <ul>
                    <li><a href="http://it.wikipedia.org/wiki/I_promessi_sposi">I promessi sposi</a></li>
                    <li><a href="http://it.wikipedia.org/wiki/Alessandro_Manzoni">Alessandro Manzoni</a></li>
                </ul>
                </p>
            </div>
            <h3><a href="#">Sezione 2</a></h3>
            <div>
                <p>e il ponte, che ivi congiunge le due rive par che renda ancor più sensibile
                all'occhio questa trasformazione e segni il punto in cui il lago cessa, e
                l'Adda ricomincia per ripigliar poi nome di lago dove le rive, allontanandosi
                di nuovo, lascian l'acqua distendersi e rallentarsi in nuovi golfi e in nuovi
                seni...</p>
            </div>
            <h3><a href="#">Sezione 3</a></h3>
            <div>
                <p>La costiera, formata dal deposito di tre grossi torrenti, scende appoggiata a
                due monti contigui, l'uno detto di san Martino, l'altro, con voce lombarda, il
                Resegone, dai molti suoi cocuzzoli in fila, che in vero lo fanno somigliare a
                una sega:</p>
            </div>
        </div>
        <!-- ===================== Tabs ===================== -->
        <div id="tabs">
          <ul>
            <li><a href="#tabs-1">Tab1</a></li>
            <li><a href="#tabs-2">Tab2</a></li>
          </ul>
          <div id="tabs-1">
          <p>Quel ramo del lago di Como, che volge a mezzogiorno, tra due catene non
          interrotte di monti, tutto a seni e a golfi, a seconda dello sporgere e
          del rientrare di quelli, vien quasi a un tratto, tra un promontorio a
          destra e un'ampia costiera dall'altra parte;</p>
          </div>
          <div id="tabs-2">
          <p>e il ponte, che ivi congiunge le due rive par che renda ancor più sensibile
          all'occhio questa trasformazione e segni il punto in cui il lago cessa, e
          l'Adda ricomincia per ripigliar poi nome di lago dove le rive, allontanandosi
          di nuovo, lascian l'acqua distendersi e rallentarsi in nuovi golfi e in nuovi
          seni...</p>
          </div>
        </div>
    </div>

Per attivare il codice JavaScript che trasforma il normale testo HTML in contenuto dinamico, si devono aggiungere due chiamate di funzione jQuery, che agiscono sugli oggetti con id=accordion e id=tabs rispettivamente. Le chiamate di funzione devono stare all'interno della funzione $(document).ready() in modo che vengano eseguite al termine del caricamento della pagina (sempre in map.phtml):

    $(document).ready(function () {
        ...
        $("#accordion").accordion();
        $("#tabs").tabs();
    });

p.mapper jQuery UI

Formattazione numeri risultato query

Il risultato di una query tramite lo strumento Seleziona viene mostrato in un dialog box, purtroppo i numeri vengono formattati come numeri con cinque decimali, anche se si tratta di numeri interi.

Per migliorare l'impaginazione bisogna modificare la funzione parseResult(). Si copia il file sorgente pm.query.js dalla directory javascript/src/ alla directory config/common/, quindi si sostituisce le seguenti istruzioni:

    if (!(noShpLink && i == 0))
        h.append(layTpl.tvalues['#default'].replace(/\$/, this)
                                           .replace(/@/, rHeader[i])
        );

con

    if (!(noShpLink && i == 0)) {
        var value;
        if (String(this).match(/^[0-9]+\.0+$/)) {
            value = parseFloat(this).toFixed(0);
        } else if (String(this).match(/^[0-9]+\.[0-9]+$/)) {
            value = parseFloat(this).toFixed(3);
        } else {
            value = this;
        }
        h.append(layTpl.tvalues['#default'].replace(/\$/, value)
                                           .replace(/@/, rHeader[i])
        );
    }

I numeri interi sono formattati senza decimali, i float con solo 3 decimali e tutto il resto rimane invariato.

Dialog box con PM.Dlg.createDnRDlg

Thanks to Armin Burger for the following details.

In plugins writing or extending p.mapper code, it is nice to use dialog boxes in the p.mapper way. Here it is an example for the PM.Dlg.createDnRDlg() function:

var dlgOptions = {
    width: 640, height: 480, left: 100, top: 50,
    resizeable: true,
    newsize: true,
    container: 'pmDlgContainer',
    name: 'PopupWindow'
};
 
var dlg = PM.Dlg.createDnRDlg(
    dlgOptions,
    'Digitize Point',
    popupUrl
);

The non-trivial options are:

newsize Defines if the dialog should always be reset to its width/height defined in the options. If false it keeps the dimensions of the state when it was closed last time.
container Defines the ID of a <div> element to add the dialog to. But don't worry too much with this, if the container with this ID does not exist it will be created automatically. You should just avoid to use ID's that might already be used for other things (like 'map'). If two dialogs use the same container then opening one will always close the other one if already opened.
name Should be unique (treat it like an ID, no blanks, no special chars), so taking the name of the plugin directory (which must be unique) is a good idea. But only important if more than one dialog are open at the same time.

Once the dialog is opened, it can be addressed (e.g. to change its content) using jQuery. In the following example if the dialog does not exists, it will be created; otherwise its content is reloaded and it is shown:

var dlgOptions = {
    width: 640, height: 480, left: 100, top: 50,
    resizeable: true, newsize: true,
    container: 'pmDlgContainer',
    name: 'PopupWindow'
};
 
var popupUrl = PM_PLUGIN_LOCATION + '/popup/popup.php?' + SID + '&key=' + val;
var dlgObject = $('#' + dlgOptions.container + '_MSG');
if (dlgObject.length < 1) {
    var dlg = PM.Dlg.createDnRDlg(dlgOptions, _p('Pop-up window'), popupUrl);
} else {
    $.ajax({
        url: popupUrl,
        type: 'GET',
        dataType: 'html',
        success: function(response) {
            dlgObject.html(response);
            dlgObject.parent().parent().show();
        }
    });
}

When using forms, p.mapper has two handy PM.Form JavaScript functions to read all the form values and to transform them into a string to be used in AJAX post or get requests:

PM.Form.getFormKVP() Returns everything in a string ready for URL concatenation, like &key1=value1&key2=value2...
PM.Form.getFormKvpObjAll() Returns everything in object/array notation, like {key1: value1, key2: value2, ...}