• Non ci sono risultati.

Prototipi per il motore di ricerca di EVT 2

6.2 Progettazione dell’interfaccia utente

6.2.2 Prototipi per il motore di ricerca di EVT 2

Sulla base delle analisi effettuate nel capitolo 5.2 e seguendo i principi descritti nelle sezioni precedenti, sono stati creati dei prototipi (mockup), ossia dei modelli grafici per la costruzione dell’interfaccia utente.

Seguendo la regola di usabilità che suggerisce di creare un’interfaccia utente con- sistente, ossia coerente nel suo insieme e rispetto alle eventuali versioni precedenti, la strada percorsa è stata quella di costruire una UI stilisticamente vicina a quella sviluppata nella prima versione di EVT (sezione 4.2.1).

Figura 6.10: Progettazione dell’interfaccia utente: il pulsante per aprire il box di ricerca.

Tenendo presente la struttura di ogni box,36 il pulsante per aprire la barra di ricer-

ca è stato posizionato nel footer del riquadro contenente il testo del documento (figura 6.10). Considerando che esso contiene gli strumenti ad azione locale, le funzionalità si 36Per la struttura in dettaglio vedere Di Pietro 2015, p. 74

riferiranno esclusivamente al box nel quale è contenuto, quindi sarà presente sia in un contesto di edizione diplomatica, sia di edizione interpretativa.

Figura 6.11: Progettazione dell’interfaccia utente: la barra di ricerca con i pulsanti per attivare/disattivare le opzioni ed l’evidenziazione dei risultati nel testo.

Premendo il pulsante si aprirà la barra di ricerca, contenente il campo di input nel quale l’utente inserirà la keyword e alcuni pulsanti con le opzioni disponibili. Partendo da sinistra abbiamo:

• il pulsante per aprire/chiudere il box contenente i risultati di ricerca; • il pulsante per attivare la ricerca avanzata;37

• il pulsante per aprire la tastiera virtuale; • il pulsante per attivare l’opzione case sensitive; • il pulsante per attivare la ricerca per parola esatta; • il campo di input;

• il pulsante per resettare il campo di input;

37Il pulsante per attivare la ricerca avanzata non compare nella versione finale del search engine, vista la decisione di inserire la funzionalità di ricerca avanzata in un riquadro globale, autonomo rispetto ai box contenenti il testo (sezione 5.2.3).

• i pulsanti “previous” e “next”, che permettono di navigare velocemente i risultati in stile browser;38

• il pulsante per avviare la ricerca.

Come mostrato in figura, durante l’inserimento di una query verranno subito evi- denziati i risultati nel testo, in modo da dare all’utente un feedback immediato.

Un aspetto importante per la ricerca in un’edizione digitale, è la possibilità di inserire caratteri non presenti nelle tastiere standard. Essi saranno posizionati in un box dedicato e vi si potrà accedere tramite l’apposito pulsante (figura 6.12).

Figura 6.12: Progettazione dell’interfaccia utente: la tastiera virtuale.

Figura 6.13: Progettazione dell’interfaccia utente: i risultati di ricerca.

38I pulsanti non risultano attivi nella versione finale, in quanto la funzionalità di navigazione veloce deve ancora essere implementata (sezione 4.2.2).

Infine i risultati, seguendo la linea di EVT 1, appariranno in un box che si aprirà premendo il pulsante per avviare la ricerca (figura 6.13).

Per quanto riguarda gli aspetti stilistici e visuali sono state seguite le regole dell’in- terfaccia già presente. Essa predilige forme chiare e semplici, utilizzando principalmente il colore blu-grigio, usato per la configurazione di default dell’applicazione. Inoltre, se- guendo la prima regola di Mandel (place users in control), che afferma che è segno di un buon design lasciare un margine di personalizzazione all’interfaccia, è stato predispo- sto un foglio di stile per permettere all’utente-editore con conoscenze informatiche di personalizzare l’interfaccia secondo il proprio gusto.39

Modifiche all’interfaccia utente

Dopo aver prodotto i mockup e aver fatto alcune considerazioni più approfondite, è stato necessario aggiungere o modificare alcuni componenti dell’interfaccia. Le mo- difiche principali hanno riguardato l’aggiunta di un pulsante per permettere all’utente- editore di avviare il processo di indicizzazione del documento e la riorganizzazione dei risultati di ricerca.

Inizialmente l’indicizzazione dei dati testuali del documento era stata concepita pri- ma del caricamento dell’interfaccia, senza un preliminare intervento dell’utente. Consi- derata però la natura completamente client-side del tool e che, quindi, tutta l’elaborazione pesa sul browser, è stato necessario rivalutare questa decisione per evitare che i tempi di caricamento dell’interfaccia fossero eccessivi. Si è pensato quindi di avviare l’indicizza- zione manualmente inserendo un bottone vicino al pulsante per aprire la barra di ricerca (figura 6.14).

Figura 6.14: Progettazione dell’interfaccia utente: il pulsante di indicizzazione.

Allo stato attuale è necessario avviare l’indicizzazione ogni volta che l’applicazione viene aperta, in quanto l’indice viene tenuto in memoria dal browser. La soluzione allo stato dell’arte non è ottimale, ragione per cui l’intenzione futura è quella di permettere l’indicizzazione solo all’utente-editore che andrà a predisporre l’edizione per la pubblica- zione, permettendogli di salvare sulla sua macchina anche l’indice in modo da non dover avviare la precedura ogni volta, a meno che non vengano fatte modifiche al documento.

Figura 6.15: Progettazione dell’interfaccia utente: i risultati della ricerca.

Per quanto riguarda invece la presentazione dei risultati della ricerca, in primo luogo è stata eliminata la paginazione a favore di una navigazione più fluida tramite scrollbar. Inoltre, considerando la possibile presenza di una collezione di documenti e, quindi, un alto numero di risultati, si è preferito organizzarli in base al singolo risultato e al nome

del documento nel quale è contenuto. In questo modo l’utente avrà una visione globale chiara fin da subito ed eviterà di dover visionare ogni singolo risultato (figura 6.15).

Parte III

Capitolo 7

L’ambiente di sviluppo

Prima di passare alla fase di implementazione vera e propria, si propone di seguito un excursus, considerando l’ambiente di sviluppo relativo a EVT 2 ed esaminando le librerie impiegate per la creazione del motore di ricerca.

7.1 Il framework AngularJS

AngularJS è un framework JavaScript open source creato nel 2009 da Miško Hevery e Adam Abrons e supportato da un team di sviluppo di Google.1 Il framework è concepito

con un’architettura modulare formata da vari componenti, ognuno dei quali ha una re- sponsabilità ben precisa. AngularJS si basa sul pattern architetturale MVC, che abbiamo visto in dettaglio nelle pagine precedenti.

Due funzionalità importanti supportate da AngularJS sono il meccanismo di dependency-injection e il data-binding2 bidirezionale (two-way data-binding). Il primo

permette di gestire in modo efficiente ed efficace le dipendenze tra i vari moduli, il se- condo permette di sincronizzare il model e la view senza ricorrere a particolari artifici di programmazione, in modo da aggiornare e mantenere sincronizzato nella vista ogni cambiamento avvenuto nei dati, e viceversa (figura 7.1).

Figura 7.1: AngularJS: two-way data-binding.

Fonte: Di Pietro 2015. 1 AngularJS:https://angularjs.org/.

Le principali componenti che caratterizzano il framework sono: • i moduli;

• i controller e gli$scope;

• le direttive; • i servizi; I moduli

Un modulo è un insieme di servizi, direttive, controller e altre funzioni che indica- no ad AngularJS la struttura del sistema e, contestualmente, le modalità di avvio.3 Essi

favoriscono la separazione dei compiti definendo una sorta di interfaccia pubblica e li- mitando la visibilità del funzionamento interno. La sintassi proposta per dichiarare un modulo è la seguente:

Estratto di codice 7.1: AngularJS: definizione di un modulo.

angular.module("moduleName", [d1, ..., dn]);

dove:

angularè un namespace globale sempre accessibile;

moduleNameè il nome che identifica il modulo;

[d1, ..., dn]è un array di 0 o più dipendenze.

Il modulo viene applicato a una specifica parte dell’applicazione grazie alla direttiva

ng-app:

Estratto di codice 7.2: AngularJS: applicazione del modulo al codice HTML. <html ng−app="moduleName"> ... </html>

3 AngularJS Module:https://docs.angularjs.org/guide/module. 101

I controller

I controller hanno il compito di gestire l’interazione tra il model e la view. Essi ven- gono solitamente associati a un elemento del DOM e quindi hanno accesso diretto allo

$scope. Uno dei loro compiti principali è quello di definire le funzionalità da utilizzare nella vista e i comportamenti di specifici elementi.4 Essendo un punto di incontro tra

dati e presentazione, in un controller non si troveranno manipolazioni dirette del DOM o dei dati.

La sintassi per definire un controller è la seguente:

Estratto di codice 7.3: AngularJS: definizione di un controller.

angular.module("moduleName", [d1, ..., dn])

.controller("ctrlName", ["$scope", function($scope) { [...]

}]);

Lo$scope

All’interno dell’oggetto $scope vengono definite le funzionalità dell’applicazione, i metodi del controller e le proprietà della view. Può essere definito come «la colla tra il controller e la view»:5 esso è il componente che gestisce la comunicazione tra vista e con-

troller, rendendo possibile l’accesso e la sincronizzazione con il model. Lo$scopeeredita tutte le proprietà e i metodi degli$scopepadri, a partire da quello associato all’elemento principale dell’applicazione, chiamato$rootScope.

Talvolta è preferibile definire i controller senza ricorrere allo $scope, utilizzando il meccanismo degli alias tramite il costrutto controller as, che permette di mantenere il codice HTML più pulito e chiaro in presenza di controller annidati. In questo caso il meccanismo di ereditarietà si perde.

Le direttive

Le direttive sono le uniche componenti Angular concepite per manipolare il DOM, intervenendo direttamente sull’interfaccia utente. Esse sono in grado di estendere il lin- guaggio HTML o di modificare un comportamento standard. AngularJS mette a disposi- 4 AngularJS Controller:https://docs.angularjs.org/guide/controller.

zione varie direttive predefinite, riconoscibili dal prefissong-, ma permette di definirne anche di nuove. Queste si possono utilizzare come elementi, attributi, classi o commenti. Solitamente una direttiva viene usata per la semplificazione del codice HTML nel caso ci siano molte ripetizioni. È possibile infatti specificare per ognuna un particolare template, definire le variabili di$scopee associarvi un controller per gestire la view.

La sintassi per definire una direttiva personalizzata è la seguente:

Estratto di codice 7.4: AngularJS: definizione di una direttiva personalizzata.

angular.module("moduleName", [d1, ..., dn]) .directive("directiveName", function() { return { restrict: string, template: string, templateUrl: string, transclude: bool, scope: bool or object, controller: string, require: string,

link: function(scope, element, attrs) {} }

});

dove:

directiveNameè l’identificativo della direttiva;

restrictindica come dovrà essere utilizzata. I valori possibile sono: A (attributo), E (elemento), C (classe), M (commento);

templateetemplateUrlindicano il codice da sostituire o aggiungere alla direttiva. Esso può essere definito in un file separato;

transcludeconsente di spostare il contenuto della direttiva all’interno del template definito, sostituendolo (se ha valoretrue) al tag marcato conng-transclude;

scopeconsente di assegnare alla direttiva un proprio scope;

controllerindica il nome del controller da associare alla direttiva;

requireconsente di indicare la dipendenza della direttiva da un’altra;

link permette di dichiarare una funzione per aggiornare il DOM o per registra- re listeners su determinati elementi per controllarne lo stato. La funzione viene eseguita dopo la trasformazione dal template alla vista.

I servizi

I servizi offrono funzionalità indipendenti dall’interfaccia utente e devono essere ac- cessibili dagli altri componenti dell’applicazione. Essi sono dei singleton, ossia oggetti istanziati una sola volta, e possono essere utilizzati per la comunicazione tra componen- ti differenti; per esempio un controller può memorizzare i dati in un servizio e un altro controller può accedere a tali dati senza richiederli nuovamente al server o senza avviare funzionalità di parsing già eseguite.

AngularJS mette a disposizione cinque modalità differenti per creare un servizio:

constant,value,service,factoryeprovider.

I primi due servizi (constantevalue) vengono solitamente utilizzati per definire va- lori primitivi o oggetti da iniettare nei componenti dell’applicazione. A differenza di

value, una costante può essere utilizzata in fase di configurazione e non è modificabile.6

La sintassi da utilizzare è la seguente:

Estratto di codice 7.5: AngularJS: definizione diconstantevalue.

/∗ CONSTANT ∗/

myModule.constant("constantName", constantObject);

/∗ VALUE ∗/

myModule.value("valueName", valueObject);

dove constantName e valueName sono i rispettivi identificativi e constantObject e

valueObjecti valori che assumono.

Estratto di codice 7.6: AngularJS: utilizzo diconstantevalue.

myModule.constant("config", {appName: "My App", appVersion: 2.0}); myModule.value("usersOnline", "0");

myModule.controller("MyController", ["config", "usersOnline", function () { console.log(config.appName, config.appVersion);

usersOnline = 15;

console.log(usersOnline); }]);

Il metodoservicepermette di creare un servizio più complesso tramite la metodolo- giatype/classtipica dei linguaggi di programmazione orientati agli oggetti. Il servizio ha la funzione di costruttore e viene richiamato da AngularJS tramite il metodonew. La definizione di un service è la seguente:

Estratto di codice 7.7: AngularJS: definizione di unservice.

angular.module("moduleName", [])

.service("serviceName", function ([d1, ..., dn]) { [...] });

dove:

serviceNameè l’identificativo del servizio;

function([d1,.., dn])è il costruttore;

[d1,.., dn]è un array di 0 o più dipendenze.

Ilfactoryè un’altra modalità di creazione di un servizio e restituisce un oggetto:

Estratto di codice 7.8: AngularJS: definizione di unfactory.

angular.module("moduleName", [])

.factory("factoryName", function ([d1, ..., dn]) {

var myFactory = { [...] };

return myFactory; });

Nell’estratto di codice 7.8,myFactoryè l’istanza dell’oggetto che rappresenta il servizio e che verrà restituita alla fine.

Estratto di codice 7.9: AngularJS: differenza traserviceefactory.

angular.module("moduleName", []) .service("myService", function () {

this.sayHello = function () { console.log("Hello"); }; });

.factory("myFactory", function () {

var greetings = {};

greetings.sayHello = function () { console.log("Hello"); }

return greetings; });

La differenza traserviceefactoryrisiede nel fatto che unservicerestituisce un’in- stanza della funzione associata al servizio e viene preferito quando si vuole definire il servizio come una classe, mentre unfactoryrestituisce solo il valore e si utilizza quando si vuole definire il servizio come istanza di un oggetto (Estratto di codice 7.9).

Infine, ilproviderè l’unico servizio che può essere iniettato nei componenti che ne hanno la necessità durante la fase iniziale di configurazione. Viene definito come un tipo custom che implementa un metodo$get.7 Esso viene istanziato come unserviceed

è disponibile a tutti i moduli che lo iniettano. La sintassi per definirlo è la seguente: Estratto di codice 7.10: AngularJS: definizione di unprovider.

angular.module("moduleName", [])

.provider("providerName", function ([d1, ..., dn]) {

this.$get = function() { [...] }; });

dove:

providerNameè l’identificativo del provider;

function([d1,.., dn])è una funzione che crea una nuova istanza di un servizio;

[d1,.., dn]è un array di 0 o più dipendenze.

Documenti correlati