Una galleria web di effetto con jQuery e prettyPhoto

Postato da ROb | nella categoria Sviluppo web | lunedì, 22 marzo 2010

8

Grazie a jQuery e ai numerosi plugin che circondano questa libreria ora è davvero semplice e divertente realizzare gallerie web leggere e di effetto.

Galleria di immagini

Oggi voglio presentarvi la galleria che ho realizzato per il sito di Giulia sfruttando jQuery e quello che considero il migliore plugin per la realizzazione di gallerie di immagini (e non solo), prettyPhoto.

Dopo aver scaricato il pacchetto dal sito ufficiale del plugin, ho preparato un pò di foto, creando anche gli opportuni thumbnail con mogrify e ho creato una pagina html che gestisse la galleria.

La realizzazione della galleria di foto, dopo aver opportunamente preparato il codice javascript della pagina, è davvero semplice. Si tratta infatti di creare degli elementi a che puntano alle immagini ingrandite che contengono al loro interno degli elementi di tipo img che visualizzano i rispettivi thumbnail.
Gli elementi di tipo a devono essere opportunamente arricchiti da un paio di attributi. L’attributo rel dichiara l’appartenenza della galleria a un determinato gruppo di foto (in sostanza, un album) mentre l’attributo title serve per sottotitolare la foto con una caption.

Ecco il codice html per ogni singola immagine:

         <li>
            <a rel='prettyPhoto[macerata]' title="La salita delle fosse" href='images/macerata_01.jpg' >
               <img src='images/thumb/macerata_01.jpg' width='100' class='thumb' border='0' />
            </a>
         </li>

Per funzionare la pagina, come anticipato, ha anche bisogno di una dichiarazione di librerie javascript in cima alla pagina:

		<script src="http://www.google.com/jsapi" type="text/javascript"></script>
		<script type="text/javascript" charset="utf-8">
			google.load("jquery", "1.3");
		</script>
		<link rel="stylesheet" href="css/prettyPhoto.css" type="text/css" media="screen" title="prettyPhoto main stylesheet" charset="utf-8" />
		<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
		<script src="js/jquery.prettyPhoto.js" type="text/javascript" charset="utf-8"></script>

e di un’inizializzazione jQuery contestuale al termine del caricamento della pagina stessa:

		<script type="text/javascript" charset="utf-8">
		$(document).ready(function(){
			$(".gallery a[rel^='prettyPhoto']").prettyPhoto({theme:'facebook'});
		});
		</script>

Ecco la pagina demo che ho realizzato con un pò di fotografie storiche di Macerata e alcune foto della mia labrador Mina.

Il progetto scaricabile è invece in questo link.

Il tema prettyPhoto utilizzato è “facebook”. Ricordo inoltre che prettyPhoto può anche essere utilizzato per visualizzare video, altri siti (tramite iframe) o contenuto html generico.

Come caricare un file sul server in AJAX

Postato da ROb | nella categoria Sviluppo web | martedì, 2 marzo 2010

2

I form html tradizionali negli anni hanno dimostrato numerosi limiti. Quelli più notevoli erano impossibilità di effettuare validazione server side, impossibilità di gestire dei campi autopopolati durante la digitazione, post completo del form senza possibilità di parzializzazione.

Ajax file upload

Tutte queste cose hanno reso il web uno strumento difficilmente utilizzabile per applicazioni che richiedessero un’elevata interazione con l’utente.
Negli ultimi anni AJAX ha rivoluzionato i tradizionali form html permettendo ai programmatori di poter dialogare agilmente con il loro backend e permettendo agli utenti di godere una più dinamica esperienza web.

Recentemente ho avuto la necessità di gestire un campo file in un form ajax. Per form ajax intendo un form che invia i suoi dati serializzati al server e non fa il post dell’intera pagina.
La tecnologia utilizzata era jQuery così ho cercato un plugin che si integrasse bene con tale tecnologia e ho trovato AJAX Upload.

Inseriamo innanzitutto gli script javascript nell’header necessari alla definizione di jQuery e del plugin AJAX Upload:

...
<head>
...
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/ajaxupload.js"></script>
...
</head>
...

A questo punto bisogna creare il div che cliccato avvierà la procedura di caricamento file:

<div id="upload_button">Upload</div>

Infine dobbiamo inizializzare i campi di tipo file all’interno del nostro form:

$(document).ready(function() {
    new AjaxUpload('upload_button_id', {action: 'uploadServletPath'});
}

Al rendering della pagina cliccando sul div upload_button si aprirà la finestra di dialogo per la scelta del file e il file sarà direttamente inviato via POST (senza però il POST dell’intera pagina) alla servlet di upload che abbiamo specificato nell’inizializzazione del componente.

Nel costruttore di inizializzazione possiamo anche passare altri parametri di configurazione e gestire alcuni eventi precedenti (o successivi) al caricamento utili per valorizzare altre variabili del form o per visualizzare la progressione del caricamento o il nome del file caricato sul server.
E’ anche possibile stabilire il tipo di risposta ricevuta dal server: html, xml o json.

Per chi fosse interessato ecco il codice Java necessario al salvataggio del file:

/*
 *	author: Roberto Rossi
 */
package it.bits4beats.servlets;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;
import java.util.Iterator;
import java.util.List;

public class UploadServlet extends HttpServlet {
	private static Log log = LogFactory.getLog(UploadServlet.class);
	public static final String DEFAULT_UPLOAD_DIR_INIT_PARAM = "DefaultUploadDir";

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * This is a default constructor for UploadServlet class.
	 *
	 */
	public UploadServlet(){
	}

	public void init() throws ServletException {
		super.init();
	}

	/**
	 * Receive a file to be uploaded and save it into filesystem
	 */
	public void doGet(HttpServletRequest request,
			HttpServletResponse response)
	throws ServletException,java.io.IOException {
		log.info("method not supported!");
	}

	public void doPost(HttpServletRequest request,
			HttpServletResponse response)
	throws ServletException,java.io.IOException {

		String defaultUploadDir = getServletConfig().getInitParameter(DEFAULT_UPLOAD_DIR_INIT_PARAM);
		if (defaultUploadDir != null && !defaultUploadDir.equals("")) {
			log.debug("> default upload dir: " + defaultUploadDir);
		}

		/* the uploading user */
		String username = request.getParameter("username");
		/* max size of file upload */
		String sizeParam = request.getParameter("sz");
		Long maxBytes = null;
		if (sizeParam != null && !sizeParam.isEmpty()) {
			try {
				/* max 5Mb file uploaded */
				maxBytes = new Long(5242880);
			}
			catch (NumberFormatException nfe) {
				/* do nothing */
			}
		}

		log.debug("remote user: " + request.getRemoteUser());
		log.debug("user principal: " + (request.getUserPrincipal() == null ? "" : request.getUserPrincipal().getName()) );
		log.debug("username: " + username);

		String status = "true";
		String message = "";
		String savedfilename = "";
		String attachmentname = "";
		String originalFilename = "";

		/* reading file streams */
		boolean isMultipart = ServletFileUpload.isMultipartContent(request);

		if (isMultipart) {

			FileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload upload = new ServletFileUpload(factory);
			List items = null;
			try {
				items = upload.parseRequest(request);

				if (items != null && items.size() > 0) {

					File uploadDirFile = null;
					String uploadDirFileRelativePath = null;

					uploadDirFile = new File(getServletContext().getRealPath(defaultUploadDir));
					uploadDirFileRelativePath = defaultUploadDir;

					Iterator itr = items.iterator();

					FileItem fileItem = null;
					FileItem filenameItem = null;

					while(itr.hasNext()) {
						FileItem item = (FileItem) itr.next();

						if (!item.isFormField()) {
							fileItem = item;
						}
						else {
							if (item.getFieldName().equals("attachmentFilename")) {
								filenameItem = item;
								log.debug("filenameItem name: " + filenameItem.getFieldName() + " valore: " + filenameItem.getString());
							}
						}
					}

					if (fileItem != null) {
						/* there is a file item in the request */
						String fileName = fileItem.getName();
						log.debug("fileItem name: " + fileName);

						if (fileItem.getName().contains("\\")) {
							log.debug("Windows file");

							/* windows file path */
							fileName = fileItem.getName().substring(fileItem.getName().lastIndexOf("\\") +1);
							log.debug("fileItem name: " + fileName);
						}

						File fullFile  = new File(fileName);
						File savedFile = new File(uploadDirFile, fileName);

						if (savedFile != null) {

							/* check file size */
							if (maxBytes != null) {
								if (fileItem.getSize() > maxBytes.longValue()) {
									FileTooBigException ftbe = new FileTooBigException();
									ftbe.setMaxSize(new Long(maxBytes.longValue()/1024/1024).toString());
									throw ftbe;
								}
							}

							if (savedFile.exists()) {
								/* we need to create a file variant, save it and send it to the user */
								String fileNameWithoutExtension = savedFile.getName().substring(0, savedFile.getName().lastIndexOf("."));
								originalFilename = fileNameWithoutExtension;
								String suffix = savedFile.getName().substring(savedFile.getName().lastIndexOf(".") + 1);

								File newFile = File.createTempFile(fileNameWithoutExtension + "_", "." + suffix, uploadDirFile);
								fileItem.write(newFile);

								log.debug("newFile: " + newFile.getAbsolutePath());
								status = "true";
								message = "OK " + newFile.length() + " byte salvati";

								/* relative file path */
								savedfilename = uploadDirFileRelativePath + newFile.getName();
								String filenameWithExt =  extractFilenameWithExtensionFromPath(savedfilename);
								attachmentname = extractFilename(filenameWithExt);
							}
							else {
								log.debug("writing file to: " + savedFile.getAbsolutePath());
								originalFilename = extractFilename(extractFilenameWithExtensionFromPath(savedFile.getAbsolutePath()));
								fileItem.write(savedFile);

								status = "true";
								message = "OK " + savedFile.length() + " byte salvati";

								/* relative file path */
								savedfilename = uploadDirFileRelativePath + fullFile.getName();
								String filenameWithExt =  extractFilenameWithExtensionFromPath(savedfilename);
								attachmentname = extractFilename(filenameWithExt);
							}
						}
						else {
							log.error("cannot create file");
							status = "false";
							message = "Errore generico di salvataggio";
						}
					}

				}
				else {
					log.debug("no item to be saved");
				}
			}
			catch (FileTooBigException ftbe) {
				status = "false";
				message = "File troppo grande, dimensione massima (Mb): " + ftbe.getMaxSize();
			}
			catch (Exception e1) {
				e1.printStackTrace();
				log.error("error in uploading");

				status = "false";
				message = "Errore generico di salvataggio";
			}
		}

		PrintWriter out = response.getWriter();

		String responseMessage = "{\"success\":" + status + ",\"message\":\"" + message + "\",\"savedfilename\":\"" + savedfilename + "\",\"attachmentname\":\"" + attachmentname + "\",\"originalfilename\":\"" + originalFilename + "\"}";
		log.debug("responseMessage: " + responseMessage);
	    out.println(responseMessage);
	}

	/**
	 * This method extract filename (with extension) from filepath
	 *
	 * @param filepath
	 * @return filename without extension
	 */
	public static String extractFilenameWithExtensionFromPath(String filepath) {
		if (filepath != null) {
			int index = filepath.lastIndexOf("/");

			if (index > 0 && index < (filepath.length() -1)) {
				return filepath.substring(index + 1);
			}
			else return null;
		}
		else {
			return null;
		}
	}

	/**
	 * This method extract filename (without extension) from filename with extension
	 *
	 * @param filepath
	 * @return filename without extension
	 */
	public static String extractFilename(String filenameWithExtension) {
		if (filenameWithExtension != null) {
			int index = filenameWithExtension.lastIndexOf(".");

			if (index > 0) {
				return filenameWithExtension.substring(0, index);
			}
			else return filenameWithExtension;
		}
		else {
			return null;
		}
	}

	class FileTooBigException extends Exception {
		private static final long serialVersionUID = 1L;

		private String maxSize = null;

		public String getMaxSize() {
			return maxSize;
		}

		public void setMaxSize(String maxSize) {
			this.maxSize = maxSize;
		}

		public FileTooBigException() {
			super();
		}

		public FileTooBigException(String message) {
			super(message);
		}
	}

}

Nel sito del plugin trovate anche una demo completa e funzionante di AJAX upload.

Utilizzare il date picker jQuery UI per i nostri campi data

Postato da ROb | nella categoria Sviluppo web | martedì, 16 febbraio 2010

39

Far inserire manualmente una data nei form è una cosa ormai poco utilizzata.
E’ buona abitudine fornire agli utenti degli strumenti che aiutano nella compilazione di tali campi.

logo jQuery UI

Ogni buon framework che si rispetti mette ormai a disposizione questi oggetti (ExtJS di cui vi parlavo qualche giorno fa non è da meno).

Oggi voglio proporvi un esempio con il datepicker del framework jQuery UI, un framework javascript nato per costruire widget e oggetti di interfaccia sfruttando solamente la libreria jQuery.

In questo esempio ho isolato dalla distribuzione di jQuery UI solamente il componente datepicker (con i suoi file javascript e i suoi fogli di stile) e l’ho utilizzato di una pagina web minimale.
Le comodità di questo componente sono il multilinguismo e la possibilità di modificarne facilmente il tema rimpiazzando alcuni file, cose che lo rendono molto appetibile nel caso di siti o applicazioni internazionalizzati e in cui l’integrazione con l’aspetto grafico dell’applicazione è fondamentale.

Per ulteriori informazioni sul componente fate riferimento direttamente al sito web oppure alla pagina specifica con la demo del componente.

esempio jQuery UI Datepicker

Ecco il codice necessario per l’integrazione del componente in una pagina web:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>bits4beats - esempio jQuery UI Datepicker</title>
	 <meta name="Description" content="Utilizzare jQuery UI Datepicker come widget per la scelta della data" />

    <script language="javascript" type="text/javascript" src="jquery.min.js"></script>
	 <script type="text/javascript" src="jquery.ui.core.js"></script>
	 <script type="text/javascript" src="jquery.ui.datepicker.js"></script>
	 <!-- INCLUDERE LA SEGUENTE LINEA PER LA TRADUZIONE DEL WIDGET IN ITALIANO -->
    <script type="text/javascript" src="ui.datepicker-it.js"></script>

    <link href="jquery-ui.css" rel="stylesheet" type="text/css" />
    <!-- SCEGLIERE IL FOGLIO DI STILE DEL TEMA PREFERITO -->
    <link href="ui.datepicker.css" rel="stylesheet" type="text/css" />

 </head>
 <body>

	<div id="datepicker">
		<label>clicca sul campo per aprire il widget</label>
		<input
			name="datepicker"
			id="datepickerId"
			type="text"
			maxlength="10"
			size="10"
		/>
   </div>

	<script type="text/javascript">
		$(document).ready(function(){
			$('#datepickerId').datepicker({ dateFormat: 'dd/mm/yy' });
		});
	</script>

 </body>
</html>

Per vedere l’effetto dal vivo potete cliccare qui, con il focus all’interno del campo data si aprirà il pannello per la selezione della data.

In questo caso il componente è stato usato in lingua italiana (linkando opportunamente il codice javascript per la traduzione).

Ecco il file zip con il codice completo dell’esempio.

Estrarre informazioni da un sito attraverso jsoup, html parser per Java

Postato da ROb | nella categoria Java, Sviluppo web | lunedì, 1 febbraio 2010

0

Ieri mi sono divertito a testare una nuova libreria in Java per il parsing di documenti HTML/XML.

Jsoup, questo il nome particolare di tale libreria, permette con una sintassi a selettori (stile JQuery) di inviduare specifici elementi del DOM di un documento html, sia locale che remoto.

Jsoup, html java parser

Dopo aver scaricato la libreria dal sito ufficiale e averla importata nel mio workspace Eclipse, ho modificato leggermente uno degli esempi proposti per provare a estrarre i titoli e gli url di tutti i post dall’homepage del mio blog (http://www.bits4beats.it).

Beh… il risultato è stato veramente interessante e ho molta voglia di farci qualcosa di più costruttivo. Pensavo addirittura a uno script o un programmino per visualizzare il posizionamento di un sito per particolari keyword su più motori di ricerca. Se avrò voglia, tempo e capacità per farlo pubblicherò un post in merito.

Per ora godetevi queste 10 righe di codice:

		Document doc = Jsoup.parse(new URL("http://www.bits4beats.it/"), 2000);

		Elements resultLinks = doc.select("div.post-title > h2 > a");
		System.out.println("Ultimi post di www.bits4beats.it con jsoup");
		for (Element link : resultLinks) {
			System.out.println();
			String href = link.attr("href");
			System.out.println("Titolo: " + link.text());
			System.out.println("Url: " + href);
		}

Nella riga 1 si crea un oggetto Document facendo il download dell’homepage del blog aspettando al massimo 2000 millisecondi.
Successivamente si cercano tutti gli elementi di tipo a figli diretti di elementi di tipo h2 figli diretti a loro volta di elementi div con classe post-title.
Per ognuno di questi elementi trovati, alle righe 8 e 9, vengono stampati rispettivamente l‘anchor text (cioè il testo cliccabile del link) e l’url del post.

Un ringraziamento allo sviluppatore del progetto, Jonathan Hedley, che ha corretto in tempi brevissimi un piccolo errore nel codice del jsoup Cookbook.

JQuery sticky toolbar, una barra in evidenza nel vostro sito

Postato da ROb | nella categoria Sviluppo web | martedì, 26 gennaio 2010

0

Ieri mi sono dilettato nella realizzazione di una toolbar di servizio per il software CMS a cui sto lavorando da oltre un anno.

Alcuni anni fa, lavorando con Symfony, avevo trovato geniale l’idea degli sviluppatori di arricchire il framework di una debug toolbar che aiutasse il webmaster nella realizzazione e nel troubleshooting del sito stesso. Ecco un’immagine di questa toolbar presa direttamente dal sito ufficiale di Symfony.

Symfony debug toolbar

La comodità di questa barra è quella di poter essere minimizzata o rimossa e contiene tutte le informazioni principali di cui un webmaster può avere bisogno durante il ciclo di sviluppo del sito stesso.

Così, spinto dalla necessità di averne una anche nel nostro CMS, mi sono cimentato nelle funzioni di animazione di JQuery e in qualche proprietà CSS. Il mio intento non era quello di replicare la barra di Symfony ma almeno di emularne i comportamenti base.

Ecco qui il risultato.

In realtà, dopo aver incluso correttamente la libreria jquery nell’head del vostro documento html e aver scelto una posizione per le immagini utilizzate nei link di chiusura e apertura della toolbar, il codice Javascript necessario al suo funzionamento si riduce a queste poche righe:

	<style>

		#toolbar {
			position: fixed;
			width: 100%;
			height: 60px;
			top: -40px;
			display: block;
			border-bottom: 2px solid black;
			opacity:0.9;
			background-color: #E5E5E5;
		}

		#toolbar #close {
			position:absolute;
			top: 40px;
			display:none;
		}

		#toolbar #open {
			position:absolute;
			top: 40px;
		}

		#toolbar #remove {
			position:absolute;
			top: 40px;
			left: 20px;
		}

		#toolbar img {
			border: 0px;
		}

		#toolbar #toolbar_text {
			font-size: 10px;
			font-family: 'Verdana',sans-serif;
			position:absolute;
			top: 2px;
			left: 2px;
			width: 100%;
		}

		#toolbar #toolbar_links {
			font-size: 10px;
			font-family: 'Verdana',sans-serif;
			position:absolute;
			top: 42px;
			left: 40px;
			width: 100%;
		}

	</style> 

	<div id="toolbar">
		<a href="javascript:;;" id="close" title="close"><img src="arrow_up.png"/></a>
		<a href="javascript:;;" id="open" title="open"><img src="arrow_down.png"/></a>
		<a href="javascript:;;" id="remove"  title="remove"><img src="delete.png"/></a>

		<div id="toolbar_text">
			A text <strong>inside</strong> the toolbar
		</div>

		<div id="toolbar_links">
			| <a href="javascript:;;">just a simple link</a>
		</div>
    	</div>

	<script type="text/javascript">
		$(document).ready(function(){
			$('#close').bind('click', function() {
				$('#toolbar').animate({top:"-40px"}, 400 );
				$('#close').hide();
				$('#open').show();
			});

			$('#open').bind('click', function() {
				$('#toolbar').animate({top:"0px"}, 400 );
				$('#close').show();
				$('#open').hide();
			});

			$('#remove').bind('click', function() {
				$('#toolbar').hide();
			});
		});
	</script>

Il codice completo è disponibile a questo indirizzo per il download.

Happy Javascript a tutti!

P.S: tale toolbar è stata testata con Firefox 3.0 e Chrom 4.0 per Linux (ma ci sono buone possibilità che funzioni con quasi tutti i browser viste le caratteristiche cross-browser del framework JQuery).

controllare il peso del bimbo tramite html e jquery

Postato da ROb | nella categoria Sviluppo web | lunedì, 18 gennaio 2010

4

Poco giorni dopo che e’ nata Giulia ho avuto l’esigenza di misurare con precisione e accuratezza il suo peso e tenerne traccia nel tempo.

All’inizio avevamo memorizzato tutto in un quadernino ma poi il quadernino diventava spesso introvabile e non aveva la cura che meritava, quindi, entusiasmato da un bellissimo plugin JQuery di nome flot ho deciso di scrivere una pagina html locale che potesse visualizzare il grafico del peso, una tabella con gli ultimi dati inseriti e che fosse allo stesso tempo semplice da aggiornare.

Ecco il risultato:

Pagina Peso Giulia

Il tutto consiste in una cartella con dentro un file html di nome peso_giulia.html e alcuni file di jquery e di alcuni suoi plugin (compreso flot).
Per impostare i pesi nei vari giorni e’ sufficiente aggiornare l’array di dati d2.
Aggiungendo o rimuovendo record come questo.

[(new Date("2009/07/01")).getTime(),3120]

Il primo campo contiene la data delle misurazione, il secondo il peso in grammi.

Dopo aver salvato il file lo sì puo’ aprire con Firefox per vedere il risultato, ovviamente potete cambiare anche tutto il resto, tra cui il nome di vostro figlio :-) .

download dello zip contenente tutti i file