Temi
Contents
Temi#
Per personalizzare l’interfaccia grafica di CKAN è necessario sviluppare un’estensione che modifichi i template forniti dall’installazione ufficiale basati su Jinja.
Tema built-in#
L’unica personalizzazione possibile del tema predefinito di CKAN è la palette di colori, modificabile come utente amministratore nella pagina di configurazione (/ckan-admin/config
) sotto la voce «Stile».
Colori disponibili:
blu (default),
rosso chiaro,
verde,
rosso scuro,
fucsia.
Nella stessa pagina è inoltre possibile personalizzare gli elementi in homepage selezionando una delle opzioni sotto la voce «Homepage»:
Introductory area, search, featured group and featured organization
Search, stats, introductory area, featured organization and featured group
Search, introductory area and stats
Per piccole modifiche allo stile delle pagine è possibile salvare un codice CSS personalizzato nella pagina di configurazione (/ckan-admin/config
) sotto la voce «CSS personalizzato». Si tratta di regole CSS globali, caricate in tutte le pagine, per cui è importante definire selettori abbastanza specifici su classi e id.
Esempio per nascondere l’immagine in homepage nella card di benvenuto: .homepage .featured { display: none; }
.
È anche possibile impostare una favicon personalizzata valorizzando la variabile d’ambiente CKAN__FAVICON
con un url assoluto a una risorsa esterna (ed. CKAN__FAVICON=https://www.estar.toscana.it/wp-content/uploads/2021/04/Logo-Estar_150x150.png
).
Temi di terze parti#
Un tema di CKAN è un’estensione, quindi se rilasciata in open source si può scaricare e installare (vedi la sezione sulle estensioni).
È molto difficile però scrivere un tema personalizzabile e abbastanza flessibile da essere riutilizzato, quindi se ne trovano molto pochi.
Sviluppo di un tema#
Lo sviluppo di un tema personalizzato richiede l’inizializzazione di un’estensione con le opportune configurazioni, la creazione e modifica dei template di pagina, del CSS e del Javascript, la gestione della localizzazione delle stringhe all’interno dei template e del codice Javascript.
Vengono in aiuto alcuni comandi della CLI di CKAN che permettono di inizializzare un’estensione vuota adatta allo scopo, di eseguire CKAN in modalità sviluppo con una serie di utility pre-caricate, di gestire la localizzazione delle stringhe.
La documentazione ufficiale mostra lo sviluppo da zero di un’estensione all’interno di un tutorial per spiegare i vari passaggi necessari per estendere le funzionalità di CKAN.
Nel nostro caso, la Open Knowledge Foundation descrive una modalità di sviluppo direttamente all’interno di un container ottimizzato per questo scopo.
Fare la build dell’immagine di sviluppo:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml build ckan
Eseguire i container in modalità sviluppo:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
Inizializzare la nuova estensione:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml exec ckan ckan generate extension --output-dir /srv/app/src_extensions
Rispondere a tutte le domande poste:
Nome dell’estensione (deve iniziare con
ckanext-
, es.ckanext-estar
)Nome dell’autore
E-mail dell’autore
Nome utente o organizzazione su Github
Descrizione dell’estensione
Tag
Nella cartella locale lab/ckan/src
apparirà la cartella della nuova estensione con il nome scelto al punto 1 (es. lab/ckan/src/ckanext-estar
).
Per modificarne i file all’interno è forse necessario modificare opportunamente i permessi della cartella.
Aggiungere alla variabile d’ambiente
CKAN__PLUGINS
il nome del plugin fornito dall’estensione appena creata (es.CKAN__PLUGINS=... nome_nuova_estensione
senza il prefissockanext-
).Riavviare il container:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d ckan
.
La versione di CKAN in esecuzione raggiungibile all’indirizzo localhost:5000
è ora in modalità sviluppo, per cui l’interfaccia presenta degli elementi interattivi che contengono informazioni di debug:
in alto a sinistra ci sono Controller e Action utilizzati dalla pagina corrente;
in basso nel footer c’è una sezione nascosta, ma visibile cliccando sul messaggio Debug;
a destra c’è un menu di debug con una serie di risorse visibili cliccando sulle varie voci.
Panoramica di un’estensione#
Nella cartella appena creata in lab/ckan/src/ckanext-estar
ci sono vari file pre-configurati:
README.md
contiene un modello di documentazione raccomandato per l’estensionesetup.py
contiene la definizione dell’estensione con le informazioni indicate interattivamente durante la creazione, è bene verificare che tutte le informazioni siano corrette e aggiornatesetup.cfg
contiene configurazioni di default per Babel, il gestore della localizzazione delle stringherequirements.txt
contiene gli eventuali pacchetti aggiuntivi da cui l’estensione dipende
Nella sotto cartella ckanext/estar/
c’è il vero e proprio codice che implementa le funzionalità dell’estensione:
plugin.py
contiene la definizione dei plugin offerti dall’estensione, sotto forma di classi che ereditano dackan.plugins.SingletonPlugin
public/
contiene i file statici che saranno serviti a partire dalla root del sito (es. fogli di stile, immagini, ecc.)templates/
contiene i template di pagina secondo la struttura originariafanstatic/
contiene i file Javascript caricati dall’estensione (es. per le funzionalità di un widget)i18n/
contiene i file di localizzazione delle stringhe
ATTENZIONE: le classi definite in
plugin.py
devono essere opportunamente elencate anche nel filesetup.py
nella variabileentry_points
File statici#
Qualsiasi file in public/
sarà pubblicato a partire dalla root del sito (vedi documentazione ufficiale).
Per esempio il file public/images/favicon.png
sarà raggiungibile all’indirizzo localhost:5000/images/favicon.png
.
Template di pagina personalizzati#
CKAN usa Jinja come motore di template e fa ampio uso del concetto di composizione. Si parte dai template di base definiti da CKAN e si sovrascrivono o si estendono opportunamente, andando a modificare solo le parti di interesse (i blocks).
Per esempio, se è attivo il primo layout «Introductory area, search, featured group and featured organization» e si crea un file templates/home/layout1.html
vuoto, questo sovrascriverà interamente l”originale e in homepage non si vedrà più il corpo centrale della pagina.
ATTENZIONE: a volte l’aggiunta di un nuovo template non ha effetti sulla pagina del sito, probabilmente a causa della cache delle pagine. Aspettare oppure fare un restart del container con
docker-compose -f docker-compose.yml -f docker-compose.dev.yml restart ckan
.
Se invece di sostituire un template, lo si vuole estendere, è sufficiente inserire in testa al file il codice {% ckan_extends %}
(un tag nel linguaggio di Jinja, si veda la documentazione ufficiale).
{% ckan_extends %}
I template possono definire dei tag block che possiedono un nome univoco e che possono essere sovrascritti indipendentemente dal resto.
Per esempio, per rimuovere solo il riquadro con il testo di introduzione dalla homepage è sufficiente sovrascrivere il solo block promoted
del layout1.html
aggiungendo all’omonimo file dell’estensione il codice {% block promoted %}{% endblock %}
(vedi documentazione ufficiale).
{% ckan_extends %}
{% block promoted %}{% endblock %}
Se invece di sostituire del tutto il contenuto di un blocco si volesse estenderlo aggiungendo elementi prima o dopo il contenuto originale, si può usare la variabile {{ super() }}
(vedi documentazione ufficiale).
{% ckan_extends %}
{% block promoted %}
<p>Intestazione</p>
{{ super() }}
<p>Piè di blocco</p>
{% endblock %}
All’interno dei template si possono definire delle variabili e poi utilizzarle all’interno delle espressioni.
Alcune variabili notevoli sono definite a livello globale, come app_globals
, accessibile anche con l’alias g
(vedi documentazione ufficiale).
{% ckan_extends %}
{% block promoted %}
<p>Intestazione di {{ g.site_title }}</p>
{{ super() }}
<p>Piè di blocco</p>
{% endblock %}
Al pari delle variabili, che vengono semplicemente stampate, nelle espressioni si possono usare metodi che vengono eseguiti.
Si chiamano helper functions, ce ne sono molte pre-definite e possono essere definite all’interno di un’estensione nel file plugin.py
.
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit
+from random import randrange
+def random_integer():
+ return randrange(1, 10)
class EstarThemePlugin(plugins.SingletonPlugin):
plugins.implements(plugins.IConfigurer)
+ plugins.implements(plugins.ITemplateHelpers)
# IConfigurer
def update_config(self, config_):
toolkit.add_template_directory(config_, 'templates')
toolkit.add_public_directory(config_, 'public')
toolkit.add_resource('fanstatic', 'estar')
+ def get_helpers(self):
+ return {
+ "estar_random_integer": random_integer
+ }
Tutte le variabili e le funzioni accessibili globalmente nei template sono elencate e descritte nella documentazione ufficiale.
I tag di Jinja supportano un sotto insieme delle funzionalità di Python, per esempio ci sono i cicli e i blocchi condizionali.
Si possono anche usare tutti i metodi dei tipi di Python, come quelli di stringhe, liste e dizionari.
La concatenazione di funzioni si fa con la |
(pipe).
Esempio completo per il file layout1.html
.
{% ckan_extends %}
{% block promoted %}
<p>Intestazione di {{ g.site_title }}</p>
{{ super() }}
{% set random_integer = h.estar_random_integer() %}
<p>Piè di blocco n. {{ (random_integer / 2) | int }}</p>
<ul>
{% for n in range(random_integer) %}
{% if n % 2 %}
<li>{{ n }}</li>
{% endif %}
{% endfor %}
</ul>
{% endblock %}
CSS personalizzato#
Per l’inclusione di fogli di stile nelle pagine si può sovrascrivere il blocco styles
del template base.html
, quello utilizzato da tutte le pagine del sito, per far caricare un file statico nella cartella public/
.
{% ckan_extends %}
{% block styles %}
{{ super() }}
<link rel="stylesheet" href="/css/estar.css" />
{% endblock %}
ATTENZIONE: recentemente è stato introdotto un metodo più avanzato per l’inclusione di CSS personalizzato che fa uso di Webassets, si rimanda alla documentazione ufficiale per tutti i dettagli.
Traduzioni personalizzate#
Il supporto per la localizzazione non è attivo di default, per cui bisogna modificare il file plugin.py
(vedi documentazione ufficiale).
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit
+from ckan.lib.plugins import DefaultTranslation
from random import randrange
def random_integer():
return randrange(1, 10)
-class EstarThemePlugin(plugins.SingletonPlugin):
+class MyCustomThemePlugin(plugins.SingletonPlugin, DefaultTranslation):
+ plugins.implements(plugins.ITranslation)
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.ITemplateHelpers)
# IConfigurer
def update_config(self, config_):
toolkit.add_template_directory(config_, 'templates')
toolkit.add_public_directory(config_, 'public')
toolkit.add_resource('fanstatic', 'estar')
def get_helpers(self):
return {
"estar_random_integer": random_integer
}
Nei template ora è possibile usare le espressioni {% trans %}{% endtrans %}
o la funzione {{ _('') }}
per la localizzazione (vedi documentazione ufficiale).
Per esempio, nel template layout1.html
.
{% ckan_extends %}
{% block promoted %}
<p>{% trans %}block header{% endtrans %}: {{ g.site_title }}</p>
{{ super() }}
{% set random_integer = h.estar_random_integer() %}
<p>{{ _('block footer') }} #{{ (random_integer / 2) | int }}</p>
<ul>
{% for n in range(random_integer) %}
{% if n % 2 %}
<li>{{ n }}</li>
{% endif %}
{% endfor %}
</ul>
{% endblock %}
Ora è necessario generare tutti i file di traduzione e inserire le stringhe localizzate.
Collegarsi al container in esecuzione:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml exec ckan bash
Entrare nella cartella dell’estensione:
cd src_extensions/ckanext-estar/
Generare il file
i18n/ckanext-estar.pot
:python3 setup.py extract_messages
(l’estrazione dei messaggi viene effettuata in tutti i file indicati nella variabilemessage_extractors
definita nel filesetup.py
)
#: ckanext/estar/templates/home/layout1.html:4
msgid "block header"
msgstr ""
#: ckanext/estar/templates/home/layout1.html:7
msgid "block footer"
msgstr ""
Inizializzare il catalogo per la lingua scelta:
python3 setup.py init_catalog -l it
Tradurre le stringhe estratte nel nuovo file
ckanext-estar.po
nella cartellai18n/it/LC_MESSAGES/
valorizzando le variabilimsgstr
#: ckanext/estar/templates/home/layout1.html:4
msgid "block header"
msgstr "Intestazione del blocco"
#: ckanext/estar/templates/home/layout1.html:7
msgid "block footer"
msgstr "Piè di blocco"
Compilare il catalogo per la lingua scelta:
python3 setup.py compile_catalog
(viene creato/aggiornato il fileckanext-estar.mo
nella cartellai18n/it/LC_MESSAGES/
)Ricaricare la homepage di CKAN
Per aggiungere la localizzazione in altre lingue è sufficiente ripetere il procedimento dal punto 4.
Con la stessa procedura è possibile sostituire le traduzioni originali di stringhe usate in CKAN, ma non necessariamente presenti nei template dell’estensione.
Per esempio si può modificare direttamente la traduzione della stringa Welcome to CKAN
contenuta nel template templates/home/snippets/promoted.html
(vedi originale) modificando il file i18n/it/LC_MESSAGES/ckanext-estar.po
.
#: ckanext/estar/templates/home/layout1.html:4
msgid "block header"
msgstr "Intestazione del blocco"
#: ckanext/estar/templates/home/layout1.html:7
msgid "block footer"
msgstr "Piè di blocco"
#:
msgid "Welcome to CKAN"
msgstr "Benvenut* su ESTAR"
Man mano che si aggiungono stringhe di localizzazione:
estrarle nel file
pot
:python3 setup.py extract_messages
aggiornare i cataloghi (file
po
):python3 setup.py update_catalog
tradurre le stringhe nei file
po
compilare le traduzioni (file
mo
):python3 setup.py compile_catalog
ATTENZIONE: per modificarne i file all’interno della cartla
i18n/
è forse necessario modificarne opportunamente i permessi.
Javascript personalizzato#
Il codice javascript eseguito da CKAN è suddiviso in moduli indipendenti e un’estensione può registrare un nuovo modulo da fare eseguire in determinate pagine / circostanze.
Si rimanda alla documentazione ufficiale per tutti i dettagli.
Laboratorio#
Sviluppiamo un tema personalizzato.