In questo articolo mostrerò come poter filtrare porzioni di testo per poi analizzare, ed eventualmente trasformare in link HTML, ogni singola parola incontrata.
Ogni termine analizzato verrà utilizzato come chiave di accesso ad un array_associativo contenente una serie di URLs, ognuna abbinata alla relativa key, per poter eseguire nel testo originale la sostituzione delle parole (e chiavi) con il link HTML alla URL recuperata dall'array.
Per fare questo creerò due classi Javascript, farò uso di un array associativo e del framework JQuery.
Separazione dei contenuti dall'interfaccia Web
Un sistema come quello che sto per mostrare contribuisce alla realizzazione della separazione dei dati, cioè i contenuti da mostrare, dall'esigenze e dalle caratteristiche dell'interfaccia grafica implementata, secondo le regole esposte dal design_pattern MVC (Model-View-Controller).
Nel mio caso, utilizzo questa soluzione per evitare di inserire codice HTML per la creazione di link nei contenuti.
Durante il caricamento della pagina HTML, in particolare quando essa è già disponibile ma non ancora completamente visibile(metodo JQuery().ready(){...}), la classe LinksGenerator filtra i contenuti delle aree di maggior interesse ed esegue la creazione dei link se avviene il match tra il termine e una chiave dell'array associativo.
Ho scelto questa soluzione fondamentalmente per i seguenti motivi:
- Mi permette di separare i contenuti da visualizzare dal modo scelto per visualizzarli;
- Mi permette di linkare risorse automaticamente in tutto il sito;
- Mi permette di rimuovere i link interrotti automaticamente in tutto il sito;
- Mi permette di concentrarmi esclusivamente sui contenuti;
- Il filtro Javascript sfrutta le risorse hardware del client utente;
Come Funziona il Filtro?
Dunque, il filtro Javascript che ho creato, per poter comprendere dove creare un link all'interno di una porzione di testo qualunque, esegue schematicamente le seguenti operazioni:
- Riceve il testo da lavorare;
- Scompone il testo in un array contenente tutte le parole presenti;
- Per ogni parola esegue un accesso all'array associativo contenente tutti i link;
- Se avviene il match chiave/termine, avviene la trasformazione della parola in link HTML all'URL estratta dall'array;
Per eseguire questo compito ho creato due classi Javascript e, per comodità, utilizzo il framework JQuery.
E' ora di iniziare ad analizzare parte del codice sorgente scritto: iniziamo dalla classe LinksGenerator.
La classe LinksGenerator
Questa classe è, tra le due create, quella di livello più alto: espone funzionalità complesse, le quali incapsulano le reali logiche di business che provvedono ognuna alla risoluzione di un specifico problema, fornisce proprietà e metodi di classe per governare le funzionalità dell'altro componente, ovvero la classe LinkDecorator, che vedremo in seguito.
Il codice sorgente che segue è ben commentato ed auto esplicativo.
/**
* Elenco dei caratteri che vengono cercati in testa
* ed in coda ad ogni singola parola.
* Utilizzato per aumentare il grado di precisione
* nel fornire la chiave di accesso alla mappa di URL.
*/
LinksGenerator.PERMITTED_CHARS
= ['.',',',':','\'',';','?','(',')','"','\n'];
/**
* Controlla se il carattere passato come parametro
* e' da considerare, o scartare, nella costruzione
* del link.
*/
LinksGenerator.isAPermittedChar = function(c){
for(var i=0;
i<LinksGenerator.PERMITTED_CHARS.length;
i++){
if(c == LinksGenerator.PERMITTED_CHARS[i])
return false;
}
return true;
}
/**
* Classe per decorare un testo senza link.
* La classe LinksGenerator provvede a sostituire
* tutte le parole che sono anche chiavi della mappa
* LinksGenerator.LINKS con i relativi link abbinati.
*/
function LinksGenerator(t){
//Proprieta' che conterra' il codice HTML
//del testo trasformato.
var html = '';
//Proprieta' che conserva il testo originale
var text = t;
//Array di tutte le parole presenti nel testo originale
var words = text.split(' ');
/*
Con ogni parola presente in words[]
prova a generare un link utilizzando una nuova istanza
della classe LinkDecorator.
*/
for(var i=0; i<words.length; i++){
var l = new LinkDecorator(words[i]);
html += l.getHtmlLink();
}
/*
Getter pubblici per accedere al contenuto delle proprietà
dall'esterno del componente.
*/
this.getHtml = function(){return html;}
this.getText = function(){return text;}
this.getWords = function(){return words;}
}
/**
* Mappa chiave/valore con l'elenco dei link
* da utilizzare in abbinamento
* alla relativa chiave
*/
LinksGenerator.LINKS = new Array();
LinksGenerator.LINKS['java']
= 'http://java.sun.com/reference/api/';
LinksGenerator.LINKS['sun']
= 'http://www.sun.com';
LinksGenerator.LINKS['jee']
= 'http://java.sun.com/javaee/';
LinksGenerator.LINKS['jme']
= 'http://java.sun.com/javame/';
LinksGenerator.LINKS['struts']
= 'http://struts.apache.org/';
LinksGenerator.LINKS['utf-8']
= 'http://it.wikipedia.org/wiki/UTF-8';
Come si può notare, la classe LinksGenerator non esegue nessuna trasformazione, contiene in se solo la logica con cui eseguire il parsing della porzione di testo passatale e con cui ricomporre il testo con le eventuali
modifiche apportate.
L'operazione di trasformazione della singola parola con il link abbinato è un compito che ho preferito delegare ad un componente specializzato, o meglio un decoratore: la classe LinkDecorator.
In questa maniera, se avrò bisogno un giorno di riutilizzare il componente per eseguire qualche altra operazione, mi basterà parametrizzare il costruttore della classe LinksGenerator in modo da accettare anche il tipo del nuovo decoratore da utilizzare.
La classe LinkDecorator
Dunque, questo componente, o decoratore, è specializzato nell'eseguire tutte le operazioni necessarie per la creazione di un link HTML a partire da una parola.
Per migliorare l'efficacia della ricerca, il componente esegue dei test e delle operazioni sulla parola ricevuta con il fine di aumentare le possibilità di trovare la chiave corretta e corrispondente nell'array associativo LinksGenerator.LINKS.
Queste operazioni prevedono l'eliminazione dei caratteri, previsti e censiti nell'array LinksGenerator.PERMITTED_CHARS, in testa ed in
coda al termine analizzato.
Passiamo ora ad analizzare il codice sorgente della classe LinkDecorator.
/**
* Classe per la creazione di un link.
* La classe LinkDecorator provvede a sostituire
* la parole in ingresso con il relativo link.
* La classe provvede anche a rimuovere caratteri
* di punteggiatura in testa ed in coda alla parola.
*/
function LinkDecorator(w){
var word = $.trim(w);
var len = word.length;
/*
Conserva il primo carattere della parola per
'limarla' nel caso non si verifichi un match immediato.
*/
var firstChar = word.charAt(0);
/*
Conserva l'ultimo carattere della parola per 'limarla'
nel caso non si verifichi un match immediato.
*/
var lastChar = word.charAt(len-1);
/*
Verifica che la parola inizi con un carattere
da rimuovere.
*/
var cleanOnStart
= LinksGenerator.isAPermittedChar(firstChar);
/*
Verifica che la parola finisca con un
carattere da rimuovere.
*/
var cleanOnEnd
= LinksGenerator.isAPermittedChar(lastChar);
var link = null;
/*
Se non sarà creato alcun link allora verrà
restituita la parola ricevuta in ingresso
con uno spazio bianco in coda.
*/
var html = word+' ';
if(! cleanOnStart){
word = word.substring(1);
}
if(! cleanOnEnd){
word = word.substring(0,len-1);
}
/*
Esegue l'accesso alla mappa per trovare
il link abbinato.
*/
link = LinksGenerator.LINKS[word.toLowerCase()];
/*
Se esiste un link abbinato al termine,
il componente creerà il codice HTML necessario
*/
if(link != null){
html = createLink();
}
/**
* Crea il codice HTML necessario per il link
* e ricompone la punteggiatura presente
* nel termine originale.
*/
function createLink(){
var t = '<a href="' + link
+ '" target="_blank">' + word
+ '<img src="./img/external_link.gif"/></a>';
if(! cleanOnStart) t = firstChar+t;
if(! cleanOnEnd) t = t+lastChar;
return t+' ';
}
/**
* Metodi getter per accedere in sola lettura
* alle proprietà del componente.
*/
this.getHtmlLink = function(){return html;}
this.getLink = function(){return link;}
}
Il componente è tanto semplice quanto funzionale.
E' da notare che il decoratore per verificare se deve eliminare caratteri di punteggiatura presenti in testa o in coda al termine, incapsula il metodo di classe LinksGenerator.isAPermittedChar().
Non rimane che mettere in funzione le classi javascript esposte: per fare questo ho creato una piccola pagina HTML di esempio.
Qui è riportato solo il codice sorgente saliente, cioè la creazione di tante istanze della classe LinksGenerator quanti sono i paragrafi presenti nel BODY della pagina HTML.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en">
<head>
<title>
Pagina di esempio del sistema di Filtraggio
e sostituzione del testo scritto in JavaScript
e presentato da Agrati Mirko.
Articolo presente sul sito dell'autore:
http://mirkoagrati.blogspot.com
</title>
<script
src="http://jqueryjs.googlecode.com/files/jquery-1.2.2.min.js"
type="text/javascript"></script>
<script type="text/javascript">
//Dichiarazione delle classi
..........................
//Utilizzo del framework JQuery per realizzare la decorazione
$(document).ready(
function(){
$('p').each(
function(){
$(this).html(
new LinksGenerator($(this).html()).getHtml()
);
}
);
}
);
</script>
</head>
<body>
<p>Ciao a tutti, programmo da molti anni con le tecnologie
SUN e ormai ho accumulato un certo <i>bagaglio</i>.</p>
<p>Programmo in Java, che utilizzo quotidianamente in ambiente
enterprise con la tecnologia JEE, ho creato applicativi
per cellulari con la tecnologia jme.</p>
<p>Mi piace lavorare seguendo il design pattern MVC,
e mi trovo molto bene in ambito web con il framework Struts.</p>
<p>Ultimamente sto attrezzando i vari applicativi
all'utilizzo del charset UTF-8.</p>
</body>
</html>
Come si nota, nel codice sorgente non sono presenti link HTML.
Potete trovare il codice sorgente e una demo funzionante cliccando qui.
Alla prossima,
MA.
0 commenti:
Posta un commento
Non ti è chiaro qualcosa?
No problem, posta il tuo dubbio ;)
..... e ricordati di firmarlo!