Archive for the 'jQuery' Category

jQ stripViewer

Friday, June 8th, 2007

Come probabilmente si é capito da vari post su questo sito, tra i miei interessi al momento c’è jQuery, questo framework JS che sta rivoluzionando il mio modo (ma non solo il mio) di scrivere javascript (il behaviour di una pagina).
Inspirato dagli effetti in dynamic HTML di questo sito e dalle ormai ‘vecchie’ interfacce in Flash tutte sliding e rimbalzanti, mi sono detto: ma perchè non farne una con jQuery?

stripViewer demo

Di componenti slideShow in js o scritte anche con jQuery già ce ne sono, quindi non mi sono inventato nulla di nuovo, ma ho creato una base su cui lavorare. L’obiettivo é arrivare alla realizzazione di un plugin jQuery per visualizzare delle immagini in una mini-gallery e tale gallery dovrebbe essere parametrica cioè funzionare a prescindere dal numero e dimensione delle foto. Un motore che vada bene per foto grandi e piccole e basato sull’ormai standardizzato concetto che il javascript nelle pagine deve essere “degradabile” e cioè che se l’utente non ha l’interprete JS abilitato nel browser, semplicemente non vede gli “effettini” ma ha accesso comunque ai contenuti.

E così ho creato uno stripViewer (no, non ci sono donnine nude; per strip intendo una ‘fascia’, e cioè un’immagine lunga di cui si vede solo una porzione), e cioè un componente che ‘muove’ con un effetto easing le immagini della gallery, rivelandone solo una alla volta. Il tutto a partire da un markup semplicissimo, come questo:

<ul>
<li><img width="200" height="100" alt="307 r/c airliner" src="stripViewer01.jpg" /></li>
<li><img width="200" height="100" alt="307 r/c airliner" src="stripViewer02.jpg" /></li>
<li><img width="200" height="100" alt="307 r/c airliner" src="stripViewer03.jpg" /></li>
<!-- eccetera -->
</ul>

Ok vediamo nello specifico che ci facciamo con questa lista. La lista è una banalissima lista flottata (così tutti i LI sono orizzontali) e all’interno di ogni LI abbiamo messo un’immagine.
Ok una lista di immagini. Bene, ci mettiamo intorno una DIV col seguente stile:


#stripViewer {
position: relative;
width: 200px;
height: 100px;
overflow: hidden;
border: 5px solid red;
margin: 2em 0;
}

Bene, si vede che questa DIV funge da maschera per il suo child (la lista UL) e ne rivela solo 200px; quindi tutte le immagini le dobbiamo fare 200px? Si, fino a che non avrò reso parametrico il valore width del container della lista…
Ok e ora?
Ora creiamo l’interfaccia. Una serie di ‘bottoni’ che comandino la gallery.
Partiamo sempre da una lista. Le liste, ricordate, sono la chiave per scrivere la struttura di un sito: tutto può essere una lista.


<ul>
<li><a href="#">&nbsp;</a></li>
<li><a href="#">&nbsp;</a></li>
<li><a href="#">&nbsp;</a></li>
<li><a href="#">&nbsp;</a></li>
<!-- tanti Li quanti sono quelli della lista immagini -->
</ul>

Ok, a questo punto aggiungiamo un pochino di javascript (jQuery).

var steps = $("#stripViewer>ul > li > img").attr("width");
$("#stripTransmitter ul").find("a").each(function(i) {
$(this).append( (i+1) );
var cnt=-(steps*i);
$(this).click( function() {
$("#stripViewer ul").animate({ left: cnt}, 750, 'expoinout');
});
});

Vediamo come funziona:

var steps = $("#stripViewer>ul > li > img").attr("width");

Qui cerchiamo la dimensione delle immagini nella lista. Si, devono essere tutte della stessa larghezza (ma lavorerò anche su questo per svincolarla dalle dimensioni fisse e renderlo così parametrico).
L’attributo width delle immagini mi torna 200px.
Ok quindi gli step da fare sono tuti da 200. Ad ogni click ’scorro’ sull’asse x di 200px o multipli di esso (a seconda del tasto premuto).

$("#stripTransmitter ul").find("a").each(function(i) {
$(this).append( (i+1) );

Qui per ogni tag A nella mia lista in “div#stripTransmitter” stampo (.append()) il numero. Otteniamo così una lista con bottoni numerati da 1 a n.

E ora la parte divertente:

var cnt=-(steps*i);
$(this).click( function() {
$("#stripViewer ul").animate({ left: cnt}, 750, 'expoinout');
});

Qui la variabile cnt vale 200(steps) moltiplicato l’iteratore (i) quindi varrà 200, 400, 600 ecc.
Sul click di questi tag A nella nostra lista in “div#stripTransmitter” usiamo il metodo .animate() per dire che ci spostiamo a sinistra, quindi negativamente (-) per i pixel passati da steps , in 750 millesimi di secondo con animazione easing di tipo “expoinout”. per funzionare necessita ovviamente di jQuery Easing Plugin v1.1 ma se usassimo i metodi built-in di jQuery ci basterebbe scrivere “slow” al posto di “expoinout” e funzionerebbe lo stesso, ma senza easing effect.

Et voilà, uno stripViewer con jQuery.
Demo1: stripViewer di un’ unica immagine lunga
Demo2: stripViewer di una serie di immagini in una lista

Enjoy!

Opera9, il posizionamento relativo degli elementi e jQuery

Wednesday, May 2nd, 2007

Esigenza:

Inserire dinamicamente un’icona, posizionarla in maniera relativa (position: relative;) senza conoscere le dimensioni del container. E fare in modo che funzioni anche su Opera

Elementi con position: relative;

Si lo so, il titolo è un pochino ‘criptico’ ma i miei colleghi developers e designers forse intuiscono che Opera9 è un browser e ‘posizionamento relativo’ ha a che fare coi CSS.

Ancora non ci siamo? Mi riferisco al bug in cui mi sono imbattuto in relazione al posizionamento ‘relativo’ di un elemento in un altro elemento di cui non è dichiarata la larghezza.

Prendiamo come esempio due siti che utilizzano questa tecnica, di
apporre una gif sopra alla thumbnail (quindi posizionato in maniera relativa) di un video: YouTube e MTV.

Anche io volevo la mia iconcina Enlarge image ma su questo mio blog, le cose non sono così semplici.

Vediamo perchè:

  1. Le immagini non sono necessariamente larghe sempre 150px
  2. Il wrapper del ‘blocco’ immagine + ombra non ha dimensione fissa
  3. Vorrei evitare di ’sporcare’ il codice inserendo “a mano” l’icona
  4. Inoltre poichè le immagini con ombra non hanno sempre la stessa dimensione (io le creo da Photoshop larghe 150px, ma come avevo spiegato l’ombra è dinamica e prescinde dalle dimensioni) ed il loro container div non ha dimensione definita, position:relative non funziona su Opera9, che mette l’icona spostata alla destra delle immagini, invece io le voglio sopra alla thumnail

Vediamo ora come ho risolto il problema, con jQuery e come appare la ns. immagine “ingrandibile”.

Io sono la thumbnail

Come potete notare se fate click sull’immagine, questa si apre nella sua versione originale (non è ingrandita, in realtà è sempre la thumbnail) e non ha l’icona. Ok, l’icona Enlarge image è stata aggiunta a runtime con jQuery.

Ma vi ricordate che ho detto? Opera vuol sapere le dimensioni del container altrimenti per lui position:relative non funziona correttamente.
Ok allora tramite il ns. jQuery possiamo sapere quanto è “largo” qualcosa:

$('img.dropshadow').width();

Questo mi ritorna la larghezza dell’immagine nel link (la thumbnail).


var tbWrapperWidth = ($('img.dropshadow').width() + 34);

Qui creo una variabile che vale la larghezza dell’immagine + il margine necessario per staccare immagine ed ombra dal paragrafo di testo.


$('div.tb-wrapper').css({ width: tbWrapperWidth });

Qui assegno al div che mi avvolge tutto, uno stile in linea che definisce la larghezza in pixel tipo: style=”width: 184px;”
E qui è il trucco. Ora Opera conosce la larghezza del wrapper e mi posiziona l’icona correttamente.

Il resto del codice, tramite il metodo .prepend(content) di jQuery aggiunge la mia icona ed il gioco è fatto.


var tbWrapperWidth = ($('img.dropshadow').width() + 30);
$('div.tb-wrapper').css({ width: tbWrapperWidth });
$("a.thickbox").prepend("<img
class='tb-larger' src='http://www.gcmingati.net/wordpress/wp-content/uploads/tblarger.gif' alt='larger view' />");
});

Enjoy!

jQuery, the book

Monday, April 23rd, 2007
jQuery, the book

E’ ufficiale e a luglio uscirà il libro “Learning jQuery: Better Interaction Design and Web Development with Simple JavaScript Techniques” di Karl Swedberg e Jonathan Chaffer e allora si che inizieremo a fare sul serio, col jQuery.

Anche perchè qui in ufficio sono tutti entusiasti (ho fatto delle demo con dei piccoli snippet di codice per qualche progetto qui e lì), ma altrettanto riluttanti ad usare la documentation o le risorse in rete perchè anche se è fatta molto bene e ricca di esempi, non parte proprio da zero, ma dà per assodati alcuni princìpi e se non si è fatto alcun ‘esperimento’ non è che jQuery sia così immediato.
Come dice il titolo, il libro è scritto per essere comprensibile per tutti coloro che hanno un background da ‘web-designer’ che non hanno molta - o nessuna - esperienza col javascript. Consideriamo che questo è un ‘altro modo’ di scrivere javascript e appunto, la potenza stà nella sintassi che va ‘digerita’ e un bel libro aiuta molto.

Flash video
accessibili e non intrusivi

Tuesday, March 20th, 2007

jQuery.Flash - sviluppato da Luke Lutman - è un potente e flessibile plugin per jQuery che serve ad aggiungere a runtime un ‘oggetto’ Flash. Come questo.

You need to upgrade your Flash Player
Google, the Master Plan. © 2007 O. Halici, J. Mayer

Pages are progressively enhanced when Flash and Javascript are available, and fallback to plain (X)HTML when they’re not — like search-engines, pdas or mobile phones. Replacements can happen as soon as the dom is ready. (X)HTML, CSS and Javascript stay where they belong — away from one another — making it easy to remove, update or swap out down the road.

Il plugin, offre la possibilità di fare dinamicamente l’embed di 5 ‘tipi’ di flash movies (Basic Embed, Flash Text-Replacement - sIFR, MP3 Player, YouTube Video, Inline Params, FlashBlock). Io mi sono ispirato con lo scritp che fa funzionare l’MP3 player.

Questa la mia versione ‘ispirata’ (ma sia chiaro, basata 90% su quanto già scritto da Lutman, ma anche 98…).


$('a[@href$="flv"]').flash(
{ src: 'flvplayer.swf'},
{ version: 8 },
function(htmlOptions) {
$this = $(this);
htmlOptions.width = '320';
htmlOptions.height = '260';
htmlOptions.flashvars.file = $this.attr('href');
htmlOptions.flashvars.image = $this.children().attr('src');
htmlOptions.flashvars.showfsbutton = 'false';
htmlOptions.flashvars.autostart = 'false';
$this.before($.fn.flash.transform(htmlOptions));
}
);

Infatti, anche se l’esempio con l’mp3 player usa l’SWF FLV 3.6 di Jeroen Wijering (che tra l’altro é il miglior .flv player attualmente reperibile), Lutman non aveva pensato ad usare questo player anche per i video.

E io, che tra elicotteri e gite fuori porta ho parecchi video che volendo potrei postare, avevo bisogno di un sistema che mi mantenga le pagine pulite e semplici da gestire e così ho ‘esteso’ lo script per le mie esigenze.

E questo metodo è perfetto.
Dovunque io voglia un video d’ora in poi, mi basterà inserire un’immagine ed un link:


<div class="flv-player-instance">
<a href="http://www.domain/media/yourpathtovideofile.flv"><img src="http://www.gcmingati.net/wordpress/wp-content/uploads/bergen.jpg"
alt="Bergen Intrepid Turbine R/C helicopter" /></a></div>

Il nostro javscript sostituisce a runtime il link con il nostro bel lettore di file flv e usa come preview l’immagine nel nostro tag ‘a’ e come path per il filmato, l’attributo ‘href’ del link.

Sounds accessible?
Enjoy!

Nota: jQuery Flash plugin su IE ha il bug “jQuery/Packer/ActiveX Bug” che sostanzialmente forza gli utenti a fare click su ogni singolo controlo ActiveX (Flash, Quicktime, etc.) in una pagina, prima di poterlo utilizzare anche se il plugin è embeddato dinamicamente via javascript. Per questo su IE bisogna prima attivare il plugin facendo click sopra al player video e poi riprodurre il filmato. E’ un bug risolvibile e comunque non credo sia bloccante… piuttosto usate Firefox!

Nota: il video qui riprodotto è stato downloadato da YouTube grazie a VideoDL.

Update: da mercoledi 13 febbraio 2008 jquery.flash non é più utilizzato per fare l’embed dinamico del player di filmati Flash Video JW FLV Media Player 3.14. Al suo posto utilizzo SFWObject (formerly known as FlashObject) ed é quindi possibile usufruire della modalità full-screen (in Firefox e Opera). Gli esempi in questo post restano comunque validi nella sintassi ma è comunque consigliabile usare SWFObject per l’embed dei file Flash, ed in particolare col JW FLV Media Player vista la disponibilità di una API JS con cui controllare il playback e non solo.

jQuery easing plugin

Monday, March 19th, 2007

Vi ricordate le famose ‘easing equations’ di Robert Penner, che diedero il via ad un mondo di interfacce - o siti - (in Flash) che si “trasformavano” nelle dimensioni e/o interagivano rimbalzando, dissolvendosi ecc. tramite tutta una serie di algoritmi che ne modificavano lo stato in maniera parametrica? Anche io nel 2004 ero flash addicted e questo ne è un esempio. Un sito, mai terminato, che doveva servire da showcase e tecnicamente rappresentava un buon punto di arrivo per i miei skill con l’ActionScript e appunto con questi effetti di molleggio, dissolvenza etc.
Ricollegandomi al precedente post sugli effetti da applicare a frammenti di codice xHTML (tags) per mezzo di javascript, o meglio per mezzo dell’incredibile e potentissimo jQuery e dei suoi plugin, ecco che oggi dal sito learningjquery.com trovo questo plugin “jQuery Easing” sviluppato da GSGD che mi fa letteralmente sobbalzare sulla sedia non appena provo gli effetti nella pagina d’esempio.

Sono certo che stimolerà la mia fantasia così come lo farà con la vostra.
Enjoy!

drop shadows con jQuery

Wednesday, March 14th, 2007

Esigenza:

Applicare un’ombra ad un’immagine qualsiasi, di qualunque dimensione, con i CSS e senza introdurre elementi extra di markup… o perlomeno che così sembri!

La mia immagine con intorno l'ombra

L’effetto è esattamente quello che vedete qui a fianco. L’ombra è un classico. Prima degli standards, che da un certo punto di vista hanno anche stimolato l’esigenza di creare stili parametrici, per così dire, coè validi per una o l’altra cosa, le immagini se avevano l’ombra era perchè dal photoshop gliela mettevi. Sin dal maggio 2004 si parla di ‘ombre’ intorno alle immagini e fatte coi CSS.

Prima di tutto bisogna dire che dal punto di vista del nostro codice (X)HTML, l’ esempio originale - introduce nel markup ben 4 div (che però non hanno valore semantico o struttuale) che “avvolgono” l’immagine, e per ognuna di esse dispone un background tagliato in un certo modo e posizionato di conseguenza. Notare che non c’è altro modo con l’(x)html ed i css per fare un’ombra!

E tutto questo, nel caso sia necessario avere un markup strutturato e semantico, probabilmente non è il metodo migliore per avere l’ombra. Se la sintassi è il vero problema, questa tecnica non è quella giusta, perchè introduce extra-markup.

Ma no, noi vogliamo l’ombra, e non vogliamo farla col photoshop su ogni immagine. E vogliamo pure mantenere il codice pulito…. cioè non vogliamo aggiungere a mano div su div intorno ad ogni immagine.

Ecco, questo è il codice (x)html che “avvolge” la nostra immagine.

<div class="wrap0">
<div class="wrap1">
<div class="wrap2">
<div class="wrap3">
<img src="immagine.gif" alt="La mia immagine con intorno l'ombra"/>
</div>
</div>
</div>
</div>

mmmh… i puristi non sembrano soddisfatti.
Non sarebbe meglio avere solo questa riga di codice?
<img src="immagine.gif" class="dropshadow" alt="La mia immagine con intorno l'ombra" />

Soluzione

Ecco come jQuery risolve il problema, introducendo a runtime (al caricamento del documento) il codice extra di cui sopra:

$(document).ready(function(){
$("img.dropshadow").wrap("<div class='wrap0'><div class='wrap1'><div class='wrap2'>" + "<div class='wrap3'></div></div></div></div>");
});

Questo codice usa il metodo .wrap() per creare le 4 div. Il fatto che le div siano aggiunte a runtime ci semplifica notevolmente la manutenzione del sito, l’aggiornamento, e la migrazione verso una nuova ipotetica grafica mantenendo inalterato il nostro markup.
Ogni div ha un background posizionato di conseguenza nei CSS, vediamo come:


/* jquery dropshadow classes */
.wrap0 {
float:left;
background: transparent url(images/shadow.gif) right bottom no-repeat;
margin: 1em 0.5em 0 -4px;
}
.wrap1 {
background:transparent url(images/shadow180.gif) no-repeat;
}
.wrap2 {
background:transparent url(images/corner_bl.gif) -16px 100% no-repeat;
}
.wrap3 {
padding: 10px 12px 12px 10px;
background:transparent url(images/corner_tr.gif) 100% -16px no-repeat;
}
div[class="wrap0"]{ /* for modern browsers */
margin: 0 1em 0 -8px;
}

Ecco.
Quindi quale è il vantaggio dell’usare jQuery per fare i drop shadow?
Che tutto si riduce al solo tag immagine <img src="immagine.gif" class="dropshadow" alt="La mia immagine con intorno l'ombra" /> a cui aggiungo solo la classe “dropshadow”.

Et voilà, drop shadows con jQuery.

multicolumn lists con jQuery

Monday, March 12th, 2007

Problema:

Creare una lista disposta su 3 colonne, senza sapere a priori quanto è lunga la lista.

E aggiungono:

Non preoccuparti di quanto è lunga la lista, ci servono 3 colonne di links. La lista andrà su un sito pubblico.

mmmh. vediamo…
L’obiettivo, come al solito, è scrivere il meno possibile. Ma non perchè sono lazy, ma perchè è una sfida. Quindi mi serve certamente 3 colonne UL. Flottate, così ottengo 3 colonne. ok.
Ma per scrivere meno, dovrei avere una sola lista….

Per creare una lista su tre colonne, se sapessi quanti elementi sono nella prima e nella seconda colonna non sarebbe difficile. Basta applicare al primo LI della mia ipotetica seconda colonna, un margin-top negativo pari all’altezza della prima, ed un margin-left sempre pari alla larghezza delle colonne (tutte e due le precedenti, e così via).


<ul id="mainlist"><li class="licol1"><a href="#">1 Exxon Mobil (XOM)</a></li>
<li class="licol1"><a href="#">2 Exxon Mobil (XOM)</a></li>
<li class="licol1"><a href="#">3 Exxon Mobil (XOM)</a></li>
<li class="licol1"><a href="#">n --- --- </a></li>
<li class="licol2"><a href="#">1 Exxon Mobil (XOM)</a></li>
<li class="licol2"><a href="#">2 Exxon Mobil (XOM)</a></li>
<li class="licol2"><a href="#">n --- --- </a></li>
<li class="licol3"><a href="#">1 Exxon Mobil (XOM)</a></li>
<li class="licol3"><a href="#">2 Exxon Mobil (XOM)</a></li>
<li class="licol3"><a href="#">n --- --- </a></li>
</ul>

Ma se questa lista non so quanto è lunga? Voglio dire, se mi possono anche dividere in tre le liste, assegnare una classe diversa per ogni blocco di lista, come posso inserire il margine negativo al punto prestabilito per fare andr sù la seconda e la terza colonna? E quale è questa misura, esattamanete in pixel?(E’ evidente che questa lista viene creata dinamicamente tramite qualcosa server-side come per es. una JSP.)
Ecco che mi viene incontro jQuery una libreria javascript ideata da John Resig e attualmente molto, molto diffusa ed estesa da molteplici plugins sviluppati dalla community.
Infatti il motto di jQuery è “write less, do more” e significa che jQuery serve per scrivere meno javascript ed ottenere di più. Tra le cose che sin dall’inizio mi hanno impressionato positivamente di questa libreria, oltre ai metodi built-in per quel che riguarda Ajax, qualche effetto e in generale la manipolazione del DOM, sono i selettori (supporta la sintassi di CSS 1-3
e basic XPath ).

E vediamo con questi selettori cosa si può fare. Ecco il codice che mi risolve brillantemente il problema delle tre liste parametriche affiancate, e del loro posizionamento.

$(document).ready(function(){
elNumberInColOne = $(".licol1").length;
var PixelCountColOne = 0;
for (i=0; i<elNumberInColOne ; i++){
PixelCountColOne += $("li.licol1:eq("+i+")").height() + 9;
}
$("ul#mainlist > li.licol2:eq(0)").css({ marginTop: - PixelCountColOne});
ElNumberInColTwo = $(".licol2").length;
var PixelCountColTwo = 0;
for (i=0; i<ElNumberInColTwo ; i++){
PixelCountColTwo += $("li.licol2:eq("+i+")").height() + 9;
}
$("ul#mainlist > li.licol3:eq(0)").css({ marginTop: -PixelCountColTwo});
});

La parte più interessante, secondo me qui da notare è il selettore inserito nel ciclo "li.licol1:eq("+i+")").height() + 9 che cerca nel LI con classe “licol1″ OGNI elemento LI e ne calcola l’altezza in px. +9 poi sono il padding top e bottom e il bordo assegnati via CSS al singolo LI (al suo A, a dire il vero).
Quindi cosa fa questo script?

  1. Prende la prima colonna, e per ogni LI ne calcola l’altezza in pixel
  2. Assegna al primo LI della seconda colonna "ul#mainlist > li.licol2:eq(0)" un margin-top negativo pari all’altezza della prima colonna. Il margin-left resta assegnato dal css.
  3. Ripete lo step 2 nella terza colonna

Et voilà. Css multicolumn lists.
Comunque allego il sorgente dell’esempio, per chi volesse usarlo.