Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script...

21
Prototype.js Gestione della libreria e dei conflitti OOP in JavaScript per creare un tooltip pag. 02 Javascript OOP 02 News scroller con Prototype 07 News Scroller: Markup HTML e regole CSS. 09 Breve introduzione a Prototype e a Script.aculo.us 13 Come evitare conflitti tra script Jquery 16 Evitare conflitti con altre librerie 20 1

Transcript of Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script...

Page 1: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Prototype.js

Gestione della libreria e dei conflitti

OOP in JavaScript per creare un tooltip pag. 02

Javascript OOP “ 02

News scroller con Prototype “ 07

News Scroller: Markup HTML e regole CSS. “ 09

Breve introduzione a Prototype e a Script.aculo.us “ 13

Come evitare conflitti tra script Jquery “ 16

Evitare conflitti con altre librerie “ 20

1

Page 2: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

OOP in JavaScript per creare un tooltip In questo articolo vedremo come realizzare un plugin JavaScript per la creazione di tooltip, permettendo agli utenti di visualizzare un testo descrittivo supplementare al passaggio del mouse sopra link o altri elementi.

L’esempio sarà il pretesto per mostrare come scrivere il codice della demo utilizzano Prototype.js e Scriptaculous, e ci offre l’occasione di esplorare l’uso e la creazione di una classe, con un approccioobject oriented più tipico di Java e C# piuttosto che di Javascript.

Grazie alla classe sarà possibile creare e personalizzare i tooltip con estrema facilità, utilizzando anche più istanze nello stesso documento, senza dover scrivere codice inutile o ridondante.

Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati all’uso dei tooltip: Cooltips, Cordinc tooltip,Tooltip-v0.2, Anatips.

Javascript OOPÈ inizialmente necessario soffermarsi su alcune funzionalità che Prototype.js aggiunge a JavaScript per la crazione delle classi. Class.create è la sintassi necessaria per la costruzione di una nuova classe: si assegna Class.create ad una variabile che è il nome della classe.

Possiamo immaginare la classe come un contenitore che ingloba e gestisce tutte le funzioni necessarie al nostro script, come una grande funzione (e in effetti lo è) che espone diversi metodi.

La struttura tipo del codice è più o meno questa: Class.create({ function1, function2, function3 }).

Grazie a Prototype.js, la classe può disporre di un costruttore, cioè di un metodo che viene eseguitoquando la classe è istanziata. Tale metodo è chiamato initialize().

Appena viene creata una nuova istanza della classe la funzione initialize() verrà eseguita e con essa anche le eventuali istruzioni contenute. Questo costruttore può accettare degli argomenti che verranno passati nel momento in cui viene dichiarata una istanza della classe tramite la keywordnew. Un tentativo di utilizzo in questo esempio:

<a id="myButton" href="#">passami sopra con il mouse per testare l'esempio</a> <script>var MyClass = Class.create({ initialize : function(button, message) { this.button = $(button); this.message = message; this.button.observe('mouseover', this.getMessage.bindAsEventListener(this)); }, getMessage : function(e) { this.newMessage = this.message + ' ( attivata dall\'evento ' + e.type + 'sul link con id ' + Event.element(e).id + ' )'; this.showMessage(); }, showMessage : function(){ this.button.up().insert(this.newMessage); }});new MyClass('myButton', 'prova inserimento Tooltip');</script>

2

Page 3: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Da osservare attentamente l’uso della keyword this, che permette rapidi riferimenti tra elementi e metodi della classe: in particolare, Prototype estende l’oggetto function con due metodi, bind() e bindAsEventListener(), che consentono alla funzione a cui sono applicati di poter passare un argomento per un’esecuzione ulteriore, senza perdere il riferimento che lo associa a un determinato oggetto. In particolare bindAsEventListener() viene utilizzato per passare al gestore l’oggetto event come primo argomento, e in modo cross-browser per assicurare la compatibilità anche con i browser più datati…

Dalla teoria alla praticaVediamo subito in un altro esempio un semplice script per i tooltip, già funzionante, con caratteristiche essenziali (come dire, il minimo indispensabile). Ecco il codice necessario da includere nell’head della nostra pagina:

<script type="text/javascript" src="js/prototype.js"></script><script type="text/javascript" src="protip-simple.js"></script> <script type="text/javascript">var startDemo = function() { $$("a.demo").each( function(node) { new Protip(node); }); } document.observe('dom:loaded', startDemo);</script> <link href="css/protip.css" rel="stylesheet" type="text/css" />

Notare il costrutto new Protip() con cui viene creata una istanza della classe al caricamento della pagina (non appena è disponibile l’albero del DOM). Il file CSS contiene le regole necessarie alla personalizzazione dell’aspetto del tooltip: è necessario assegnare un posizionamento assoluto e un valore di z-index sufficientemente elevato. Lo script percorre il documento alla ricerca di tutti i tag <a> con classe “demo” e per ognuno invoca una nuova istanza della classe Protip. Come abbiamo visto nell’esempio precedente, questa classe è costituita da varie funzioni figlie ognuna adibita ad un diverso compito:

• initialize(): è il costruttore che accetta come argomento l’elemento su cui vogliamo mostrare il tooltip. Di fatto attiva il nostro script invocando le funzioni addObservers() e setupProtip().

• addObservers(): semplicemente questa funzione cattura gli eventi del mouse dell’utente sull’elemento. Gli eventi che ci interessano, sono tre: mouseover, mouseout e mousemove; al verificarsi di ognuno è associata una funzione nel nostro script. Fare attenzione al binding delle funzioni e all’uso del metodo di Prototype event.observe.

• setupProtip(): è la funzione che genera il codice HTML del tooltip e lo inietta attraverso il DOM. In pratica, per ogni tag <a> con classe “demo” inserisce dinamicamente e temporaneamente nasconde un <div> (che costituisce il tooltip). Il contenuto del tooltip èpreso direttamente dall’attributo title del tag <a>. Anche in questa funzione vengono utilizzati dei metodi proprietari di Prototype (element.insert(), element.update() e lo stesso costrutto new element()).

• showProtip(): viene mostrata il tooltip in seguito all’evento mouseover dell’utente sull’elemento (element.show()).

3

Page 4: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

• hideProtip(): di conseguenza nasconde il tooltip in seguito a un evente mouseout dal relativo elemento (element.hide()).

• moveProtip(): questa funzione intercetta il movimento del mouse sopra l’elemento e regola il posizionamento del tooltip. Le coordinate del mouse vengono ottenute grazie ai metodi di Prototype Event.pointerX() ed Event.pointerY() e a al passaggio dell’oggetto event catturato dalla funzione addObservers().

Ecco il codice codice della classe Protip contenuto in protip-simple.js:

var Protip = Class.create({

initialize: function(element){ this.element = $(element); this.addObservers(); this.setupProtip(); },

setupProtip: function() { this.content = this.element.readAttribute('title'); this.element.title = ''; this._protip = new Element('div', {'class':'protip'}).update(this.content); $$('body')[0].insert(this._protip.hide()); }, addObservers: function() { Event.observe(this.element, "mouseover", this.showProtip.bind(this)); Event.observe(this.element, "mouseout", this.hideProtip.bind(this)); Event.observe(this.element, "mousemove", this.moveProtip.bindAsEventListener(this)); }, showProtip: function() { this._protip.show(); }, hideProtip: function() { this._protip.hide(); },

moveProtip: function(event){ this.mouseX = Event.pointerX(event); this.mouseY = Event.pointerY(event); this._protip.setStyle({ top:this.mouseY + 20 + "px", left:this.mouseX + 15 +"px" }); }

});

Un codice più versatile con le opzioni

Lo script sopra esaminato è un esempio di ordine e modularità ma ancora non rende merito delle effettive possibilità dell’uso delle classi Javascript di Prototype. Un code-pattern tipico nella creazione di plugin con Prototype prevede il passaggio nella funzione costruttore initialize() di un secondo argomento (options) che può contenere un’hash di parametri opzionali (coppie chiave/valore). Se le coppie sono presenti, vengono utilizzati i valori specificati nella dichiarazione

4

Page 5: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

della nuova istanza della classe, altrimenti vengono presi i valori di default. In questo modo è possibile modificare i parametri dello script senza dover intervenire in più parti: con poche righe di codice è possibile creare diverse istanze personalizzate della classe nello stesso documento. Per attuare queste migliorie nello script precedente è quindi necessario modificare la funzione initialize() e inserire la funzione setOptions(), che può essere considerata come il pannello di controllo della classe, permettendo di configurare le tooltip in base alle diverse preferenze.

initialize: function(elemetn,options){ this.element = $(element); this.setOptions(options);

this.addObservers(); this.setupProtip(); },setOptions: function(options) { this.options = { maxWidth: '', offsetX: 15, offsetY: 20, opacity: .75, appearDuration: 0.5, hideDuration: 1.0 }; Object.extend(this.options, options || {}); }

Le varie opzioni ora disponibili consentono di integrare nello script delle funzionalità aggiuntive. Nel caso di questo secondo esempio è stato incluso anche Scriptaculous (per la precisione sono sufficienti scriptaculous.js ed effect.js) per applicare un effetto fade all’apparizione della tooltip (Effect.Appear ed Effect.Fade). I parametri opzionali opacity, appearDuration e hideDuration servono a personalizzare questo effetto. Vediamo quindi come sono cambiate le funzioni showProtip() e hideProtip():

showProtip: function() { this._protip.currentEffect && this._protip.currentEffect.cancel(); this._protip.currentEffect = new Effect.Appear(this._protip, { duration: this.options.appearDuration, to: this.options.opacity });},hideProtip: function() { this._protip.currentEffect && this._protip.currentEffect.cancel(); this._protip.currentEffect = new Effect.Fade(this._protip, { duration: this.options.hideDuration });}

Tramite il parametro opzionale maxWidth possiamo limitare la larghezza del tooltip, mentre con offsetX/offsetY regoliamo la distanza del tooltip dal puntatore del mouse. Le ultime modifiche al codice riguardano quindi le funzioni setupProtip() e moveProtip() con cui si assicura uncorretto posizionamento della tooltip anche rispetto alle dimensioni orizzontali della finestra del browser. Per ottenere la larghezza del tooltip viene utilizzato il metodo di Prototype element.getWidth(), che ci restituisce un valore espresso in px.

setupProtip: function() { this.content = this.element.readAttribute('title'); this.element.title = ''; this._protip = new Element('div', {'class':'protip'}).update(this.content);

5

Page 6: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

$$('body')[0].insert(this._protip.hide()); if (this.options.maxWidth!='' && this._protip.getWidth()>this.options.maxWidth) { this.protipWidth = this.options.maxWidth; } else { this.protipWidth = this._protip.getWidth(); } },moveProtip: function(event){ this.mouseX = Event.pointerX(event); this.mouseY = Event.pointerY(event); if((this.protipWidth+this.mouseX)>=(Element.getWidth(document.body)-this.options.offsetX)) { this.mouseX = (this.mouseX - this.protipWidth) - 2*this.options.offsetX; } this._protip.setStyle({ top:this.mouseY + this.options.offsetY + "px", left:this.mouseX + this.options.offsetX + "px" }); }

Ecco l’esempio completo in opera: naturalmente è possibile applicare la tooltip non solo su dei link,ma anche su div, input, e su qualunque altro tag provvisto di un attributo title. La compatibilità cross-browser degli script presentati è buona: Firefox, Safari, Chrome e le varie versioni di IE (6, 7 e 8). Proprio per correggere alcuni problemi del framework con l’ultima versione del browser Microsoft, consiglio di utilizzare da subito la bleeding-edge version di Prototype (1.6.1 RC2). In finale il link per il download di tutti gli esempi.

Riguardo alla parte teorica trattata nell’articolo, non è stata affrontata l’ereditarietà delle classi in Prototype, in particolare la possibilità di creare delle sottoclassi a partire da una classe principale e le funzionalità di Object.extend e Class#addMethods, con cui possiamo creare metodi “on the fly” dove necessario: sono strumenti molto utili e potenti per lo sviluppatore. Poco male comunque, mi riprometto di approfondire presto questi apetti in un nuovo articolo: stay tuned!

6

Page 7: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

News scroller con PrototypeQuesto articolo è la continuazione di Tooltip con le classi di Prototype: la lettura del precedente articolo è consigliata, inquanto alcune nozioni di base sulla creazione delle classi Javascript sono date per assunte. Approfondiremo lo scripting

object oriented consentito dall’utilizzo del framework Prototype attraverso la crezione di un esempio pratico: un News Scroller (verticale e orizzontale) non intrusivo, imitando il comportamento ottenuto con il tag <marquee>, un elemento deprecato che non è mai entrato negli standard del W3C. Interessantee al riguardo anche l’articolo “News scroller in Javascript non intrusivo” di Cesare Lamanna, il cui esempio (disponibile solo in versione verticale) non richiede alcuna libreria di supporto. Desidero menzionare anche il post originale sull’ereditarietà delle classi in Prototype, su Syntactic Sugar, che è senza dubbio un ottimo approfondimento sull’argomento della programmazione ad oggetti in Javascript.

Classes Inheritance con PrototypeVediamo qualche esempio teorico su alcune delle funzionalità che utilizzeremo nel News Scroller. Con la versione di Prototype 1.6 si è aggiunta la possibilità di estendere le classi con facilità, da unaclasse principale a delle sottoclassi discendenti che ne ereditano i metodi, gli oggetti e le relative proprietà. Nel precedente articolo abbiamo conosciuto abbastanza approfonditamente la sintassi di Class.create() per la creazione di una classe e il suo metodo costruttore initialize(); diciamo ora che Class.create() accetta un numero arbitrario di argomenti. Se il primo è un’altra classe, la nuova classe eredita da essa e la estende. Tutti gli altri eventuali argomenti sono passati come metodi dell’istanza. Subito un po’ di codice dove creiamo una classe base e una secondaria derivata da essa:

var baseClass = Class.create({ initialize:function(){ // Costruttore },

somefunction : function(){ $$('body')[0].insert("<p>Hai eseguito somefunction in una istanza di baseClass</p>"); },

anotherfunction : function(){ $$('body')[0].insert("<p>Hai eseguito anotherfunction in una istanza di baseClass</p>"); } })

var BaseClassExtended = Class.create(baseClass, { initialize:function(){ },

somefunction : function(){ $$('body')[0].insert("<p>Hai eseguito somefunction in una istanza di BaseClassExtended</p>"); },

anotherfunction : function($super){ $super(); $$('body')[0].insert("<p>Hai eseguito anotherfunction in una istanza di BaseClassExtended</p>"); }})

7

Page 8: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Proviamo per prima cosa (esempio), il funzionamento della classe principale baseClass, istanziandola nella funzione startDemo() e invocando il metodo della classe somefunction():

var startDemo = function() { var firstInstance = new baseClass(); firstInstance.somefunction(); }

Event.observe (window, 'load', startDemo);

Il risultato ottenuto non è niente di eccezionale, viene inserito nel documento un semplice paragrafoche ci conferma la nostra azione: “Hai eseguito somefunction in una istanza di baseClass”. Continuiamo con un secondo esempio; stavolta prendiamo in esame la classe che estende la principale, BaseClassExtended, invocando il medesimo metodo somefunction(): per far questo bisogna modificare il contenuto della funzione starDemo() con una nuova istanza:

var startDemo = function() { var secondInstance = new BaseClassExtended(); secondInstance.somefunction(); }

In questo caso, il paragrafo inserito dallo script ci notifica che la classe estesa ha sovrascritto il metodo somefunction() originario della classe base: “Hai eseguito somefunction in una istanza di BaseClassExtended”.

Il prossimo passo puo essere allora tentare di eseguire entrambe le funzioni, quella estesa e quella della classe base, senza sovrascritture. Bisogna modificare la funzione starDemo() come sotto: viene creata un’altra istanza di BaseClassExtended e viene invocato il metodo comune delle due classi anotherfunction(): ecco il terzo edultimo esempio.

var startDemo = function() { var thirdInstance = new BaseClassExtended(); thirdInstance.anotherfunction(); }

Semplicemente abbiamo ottenuto il risultato voluto (cioè l’esecuzione di entrambe le funzioni), vengono infatti inseriti due paragrafi: “Hai eseguito anotherfunction in una istanza di baseClass”, “Hai eseguito anotherfunction in una istanza di BaseClassExtended”. Tutto questo però è avvenuto solo grazie all’uso della funzione $super(), passata come argomento nel metodo della classe estesa (BaseClassExtended.anotherfunction): $super è a tutti gli effetti una parola riservata di Prototype.

Con gli esempi precedenti abbiamo già visto qualcosa, ma la loro semplicità non giustica il ricorso all’ereditarietà delle classi Javascript di Prototype. Un codice un po’più complesso, e la necessità di renderlo più versatile e flessibile, uniti a un esempio più concreto, possono rendere meglio l’idea degli effettivi benefici apportati da questi strumenti se utilizzati nei nostri script. L’occasione si presenta subito nel caso della realizzazione del News Scroller. Ho pensato infatti di strutturare lo script in modo da utilizzare tre classi. Una classe base, per eseguire le operazioni comuni e le altre due, estese dalla classe principale, ognuna con metodi specifici rispettivamente per lo scroll in orizzontale e per quello in verticale.

8

Page 9: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

News Scroller: Markup HTML e regole CSS.La struttura HTML utilizzata è molto semplice, e può essere la medesima per entrambi i tipi di

scroll: è essenzialmente necessario inserire il contenuto che vogliamo scrollare in due <div>, il piùesterno dei quali, di dimensioni definite, è il riquadro in cui visualizzare il contenuto in movimento. Vediamo subito un esempio anche se incompleto: da notare, a parte la mancanza di Javascript, che ènecessario innanzitutto nascondere la parte di contenuto che eccede le dimensioni del div contenitore: assegnamo allora il valore hidden alla proprietà CSS overflow di questo elemento.Grazie a Javascript, potremo ciclicamente spostare a piccoli passi il div interno verso l’alto o verso sinistra, a seconda della direzione del movimento, e rendere visibile la parte nascosta. Se lo scroller da utilizzare è quello orizzontale, è necessario aggiungere qualche regola CSS per gli elementi del contenuto ( nel nostro caso dei paragrafi), che in pratica devono essere affiancati l’uno all’altro senza andare a capo. Basta modificarne le proprietà CSS float e display per renderli “inline”.

/* scroller orizzontale */#example { border:1px solid #000; width:700px; height:30px; overflow:hidden;}

#example p { padding:0 50px; margin:0; width:auto; display:inline; float:left; white-space:nowrap; line-height:30px;}

/* scroller verticale */#example2 { border:1px solid #000; background:#E1F0F9; width:300px; height:150px; overflow:hidden;}

#example2 div { padding:0 10px;}

News Scroller: il codice Javascript.

Possiamo subito analizzare il codice della classe newsMarquee, che è la classe principale dello script del News Scroller. Le varie funzioni che la compongono saranno utilizzate dalle sue classi “figlie” estese (horizontalMarquee e verticalMarquee):

• initialize(): è il metodo costruttore della classe che accetta due argomenti: l’elementocontenitore dello scroller di news e un hash di opzioni per il settaggio e la personalizzazione dello script (è possibile intervenire sulla velocità e sul controllo del movimento). Questa

9

Page 10: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

funzione si occupa tra le altre cose di distanziare opportunamente il div interno al contenitore per assicurare una corretta visualizzazione del contenuto in scorrimento, assegnandogli un padding laterale o verticale pari rispettivamente alla sua larghezza o altezza.

• addObserver(): nel caso si sia deciso di consentire all’utente di controllare il movimento delle news, questa funzione intercetta gli eventi mouseover e mouseout del mouse sul riquadro dello scroller, e richiama di conseguenza i metodi playScroll() e pauseScroll().

• playScroll(): di fatto “attiva” (o riattiva in seguito a un’eventuale pausa dello scroll) il movimento richiamando il metodo startScroll().

• startScroll(): questa funzione utilizza il metodo di prototype PeriodicalExecuter ( l’equivalente di setInterval in semplice Javascript) che permette di eseguire ciclicamente una funzione. PeriodicalExecuter accetta due argomenti, la funzione da invocare (nel nostro caso executeScroll(), metodo delle classi figlie) e l’intervallo di esecuzione (in secondi).

• pauseScroll(): questo metodo della classe ferma l’esecuzione in loop infinito della funzione executeScroll() richiamata da PeriodicalExecuter.

var newsMarquee = Class.create({

initialize: function(element,options) { this.element = $(element); this.innerDiv = this.element.down('div'); this.options = { speed: 3, control: true }; Object.extend(this.options, options || {}); this.playScroll(); if (this.options.control) { this.addObserver(); } }, addObserver: function() { this.element.observe('mouseover', this.pauseScroll.bind(this)); this.element.observe('mouseout', this.playScroll.bind(this)); }, playScroll: function(){ this.scrolling = true; this.startScroll(); }, pauseScroll: function(){ if (this.timeout) { this.timeout.stop(); this.scrolling = false; } }, startScroll: function(){ if (this.scrolling) { this.timeout = new PeriodicalExecuter(function(){ this.executeScroll();

10

Page 11: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

}.bind(this), this.options.speed/100); } } });

Le classi secondarie ereditano questi metodi dalla classe principale ed in più la estendono con metodi propri specifici per il tipo di movimento :

• initialize(): ogni classe estesa dispone di un proprio metodo costruttore che grazie all’utilizzo della già menzionata funzione $super consente di eseguire ulteriori istruzioni senza sovascrivere il metodo costruttore della classe superiore.

• executeScroll(): questa funzione viene richiamata ciclicamente da PeriodicalExecuter secondo l’intervallo di tempo specificato: in pratica si occupa di spostare lo scroller di 1px alla volta ad ogni esecuzione. A seconda del movimento orizzontale o verticale, si interviene sulle proprietà Javascript dell’elemento scrollLeft o scrollTop.

var horizontalMarquee = Class.create(newsMarquee,{

initialize: function($super,elemen,options) { $super(element,options); this.initialWidth = this.element.getWidth(); this.childWidth = 0; this.childs = this.innerDiv.childElements(); this.childs[0].style.paddingLeft= this.initialWidth+'px'; this.childs[this.childs.length-1].style.paddingRight= this.initialWidth+'px'; this.childs.each(function(node) { this.childWidth += node.getWidth(); }.bind(this) ) this.innerDiv.style.width = this.childWidth+'px'; }, executeScroll: function() { if (this.element.scrollLeft > (this.element.scrollWidth-this.initialWidth)) { this.element.scrollLeft = 0; } this.element.scrollLeft = this.element.scrollLeft+5; }

});

var verticalMarquee = Class.create(newsMarquee,{

initialize: function($super,element,options) { $super(element,options); this.initialHeight = this.element.getHeight(); this.innerDiv.style.paddingTop = this.initialHeight+'px'; this.innerDiv.style.paddingBottom = this.initialHeight+'px'; }, executeScroll: function() { if (this.element.scrollTop>=(this.element.scrollHeight-this.initialHeight)) { this.element.scrollTop=0;

11

Page 12: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

} this.element.scrollTop = this.element.scrollTop+1; }

});

E’ tutto, non rimane che istanziare contemponeareamente le classi estese (se vogliamo utilizzare entrambi i tipi di scroll) al caricamento della pagina e provare l’esempio:

Event.observe (window, 'load', function(){ new horizontalMarquee('example'); new verticalMarquee('example2');});

E’ possibile intervenire nel codice CSS per personalizzare la formattazione delle news nel modo chepiù ci aggrada; è anche possibile modificare le dimensioni dello scroller per inserire altri elementi, come delle immagini, ed ottenere un piacevole effetto di visualizzazione. Ho verificato il corretto funzionamento degli script proposti su piattaforma Windows nei seguenti browser: Internet Explorer 6, 7 ed 8, Mozilla Firefox, Opera e Safari. Il codice e gli esempi sono disponibili per il download.

12

Page 13: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Breve introduzione a Prototype e a Script.aculo.us

In questa brevissima guida introduco sinteticamente• Prototype e • Script.aculo.us

Prototype è decisamente una libreria molto potente e sebbene io tenda a preferire JQuery per la suasemplicità, Prototype non può non essere considerato come uno dei migliori framework javascript disponibili.

Per chi non sa cos’è un framework sappia che sono collezioni di librerie, componenti, e altre risorsecostruite sopra una data piattaforma per semplificare lo sviluppo di un’applicazione su quella piattaforma.

Per chi ha letto Effective UI, la definizione è

The terms “platform” and “framework” are often used inconsistently and interchangeably. We consider platforms to be the foundational basis for a product, including the language used to code it.Frameworks are collections of libraries, components, and other resources built on top of a given platform to simplify the development of applications on that platform.

Jonathan Anderson, John McRee, Robb Wilson

In questo modo non c’è la necessità di “reinventare la ruota”, come dicono gli anglosassoni, e si puòutilizzare del buon codice, molto performante e ben testato per ovviare alle esigenze più comuni.

Prototype è una libreria abbastanza invadente. Essendo javascript, una simulazione di un linguaggio ad oggetti, non ha classi reali dove vengono definiti i tipi primitivi e Prototype tra le sue funzionalità ha la possibilità di estendere i tipi primitivi di javascript (es. l’oggetto String, l’oggetto Array, ecc..).

Questo rende Prototype prepotente rispetto, ad altre librerie che qualora si trovassero ad essere richiamate all’interno della stessa pagina potrebbero non funzionare più correttamente.

Prototype permette sostanzialmente di:

agire sul contenuto manipolando il DOM estendere le funzionalità dei tipi nativi gestire gli eventi utilizzare la tecnologia AJAX

13

Page 14: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

gestire la UI nel modo più efficiente estendere se stessa con nuovi moduli

Il contenuto html ovvero gli elementi della pagina vengono richiamati attraverso dei selettori.

Ci sono 3 tipi di selettori

$() -> Ritorna un elemento o una serie di elemento attraverso ID dell’elemento $$() -> Ritorna un elemento o una serie di elemento attraverso un espressione CSS3 $F() -> Ritorna valori di un elemento form

Una volta selezionato l’elemento html, Prototype da la possibilità di:

1. Manipolare il contenuto 2. Navigare nel DOM (spostarsi con facilità nel DOM) 3. Modificare le proprietà dello stile CSS 4. Gestire gli eventi 5. Mantenere un aspetto uniforme su più piattaforme (cross browsing) 6. Miscellanee (altre caratteristiche)

La sintassi con cui si utilizza Prototype è abbastanza semplice:

document.observe(“dom:loaded”, function(){ $(“myLink”).observe(“click”, function(){ //fa qualcosa });});

Con

document.observe(“dom:loaded”, function(){

sto dicendo: appena la pagina è stata caricata, esegui queste istruzioni

$(“myLink”).observe(“click”, function(){ //fa qualcosa});

Non si tratta che di un listener, on metodo applicato ad un oggetto che permette di intercettare un evento. In questo caso si tratta dell’evento “Click”

Quando l’elemento “myLink” viene cliccato viene eseguita una funzione, in questo caso //fa qualcosa

Scriptaculous è una libreria che si basa ed estende Prototype e serve per aggiungere animazione e maggiore controllo della UI alle applicazioni web.

Basandosi su Prototype implica che per funzionare necessita di essa.

Scaricando lo zip dal sito ufficiale di Script.aculo.us, all’indirizzo http://script.aculo.us/downloads, troverai al suo interno diverse cartelle:

• Lib, contiene Prototype • Src, contiene i file di Script.aculo.us

14

Page 15: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Diversamente da Prototype, Script.aculo.us è suddivisa in diversi file. Ogni file serve ad estendere una funzionalità specifica.

Esiste poi il file Scriptaculous.js che racchiude tutte le funzionalità, ma è sempre consigliato di utilizzare solo le librerie di cui necessiti, per agevolare la fruizione dei tuoi contenuti ai tuoi utenti.

Ecco cosa può fare per te Script.aculo.us

• EFFETTI ANNIMATI (effects.js) Fornisce 25 effetti visuali diversi e 7 transizioni

• DRAG & DROP (dragdrop.js) Rende gli elementi mobili, definisce are snap, e permette il sorting degli elementi

• IN PLACE EDITING (controls.js) Crea autocompleter e oggetti modificabili attivabili al click

• CONTROLLI TENDINA (slider.js) Permette di creare tendine verticali e orizzontali e altri oggetti

• DOM COSTRUTTORE (builder.js) Semplifica la creazione di elementi del DOM e migliorale performance di cross browsing

• AUDIO (sound.js) Permette di gestire suoni senza la necessità di plugin flash

15

Page 16: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Come evitare conflitti tra script JqueryIn questa breve guida vi svelero’ un piccolo trucco per far “convivere” diversi script Jquery nella stessa pagina o usare contemporamente le librerie Prototype.

Molte volte infatti, data la chiamata ricorrente di funzioni e variabili col $, gli script Jquery vanno letteralmente in conflitto rendendo il sito instabile o addirittura non funzionando correttamente.

Ricordiamo intanto che, per chi non lo sapesse la funzione $() presente in quasi tutti gli script e’solo un ALIAS. Per far funzionare tutti gli script bastera’ quindi usare la pratica e comodamodalita’ “no conflict()” che permette di sostituire il dollaro con la parola “jQuery”. In questomodo viene differenziata la variabile (o la funzione) dalle precedenti usate nella pagina web.

123456789

<script>jQuery.noConflict();// Usa jQuery con jQuery(...)jQuery(document).ready(function(){ jQuery("#foto").show("slow");});// Codice di una libreria con $(...)// ...</script>

In questo modo e’ possibile, come vedete chiaramente dall’esempio sovrastante, usare due codici jQuery che altrimenti andrebbero in conflitto. La soluzione e’ utile anche (e sopratutto) se state usando contemporaneamente anche le librerie Prototype (anch’esse usano le variabili $ ).

Esistono anche ulteriori metodi, ma ho pensato di illustrarvi quello piu’ semplice da attuare. Per altri metodi vi rimando alla pagina ufficiale.

NOTA PERSONALE: Ho trovato molto utile questa soluzione sopratutto usando Joomla e Virtualmart. Il template da me costruito aveva delle animazioni con jQuery che non facevano reagire il carrello quando si cliccava su “aggiungi”.

16

Page 17: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

jQuery.noConflict()

Description: Relinquish jQuery's control of the $ variable.

jQuery.noConflict( [removeAll ] ) version added: 1.0 removeAll

Type: Boolean

A Boolean indicating whether to remove all jQuery variables from the global scope (including jQuery itself).

Many JavaScript libraries use $ as a function or variable name, just as jQuery does. In jQuery's case, $ is just an alias for jQuery, so all functionality is available without using $. If you need to use another JavaScript library alongside jQuery, return control of $ back to the other library with a call to $.noConflict(). Old references of $ are saved during jQuery initialization; noConflict() simply restores them.

If for some reason two versions of jQuery are loaded (which is not recommended), calling $.noConflict( true ) from the second version will return the globally scoped jQuery variables to those of the first version.

123456

<script src="other_lib.js"></script><script src="jquery.js"></script><script>$.noConflict();// Code that uses other library's $ can follow here.</script>

This technique is especially effective in conjunction with the .ready() method's ability to alias the jQuery object, as within callback passed to .ready() you can use $ if you wish without fear of conflicts later:

123456789

<script src="other_lib.js"></script><script src="jquery.js"></script><script>$.noConflict();jQuery( document ).ready(function( $ ) { // Code that uses jQuery's $ can follow here.});// Code that uses other library's $ can follow here.</script>

If necessary, you can free up the jQuery name as well by passing true as an argument to the method. This is rarely necessary, and if you must do this (for example, if you need to use multiple versions of the jQuery library on the same page), you need to consider that most plug-ins rely on thepresence of the jQuery variable and may not operate correctly in this situation.

17

Page 18: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Examples:

Example: Map the original object that was referenced by $ back to $.

12345

jQuery.noConflict();// Do something with jQueryjQuery( "div p" ).hide();// Do something with another library's $()$( "content" ).style.display = "none";

Example: Revert the $ alias and then create and execute a function to provide the $ as a jQuery alias inside the function's scope. Inside the function the original $ object is not available. This works well for most plugins that don't rely on any other library.

12345678

jQuery.noConflict();(function( $ ) { $(function() { // More code using $ as alias to jQuery });})(jQuery); // Other code using $ as an alias to the other library

Example: Create a different alias instead of jQuery to use in the rest of the script.

1234567

var j = jQuery.noConflict(); // Do something with jQueryj( "div p" ).hide(); // Do something with another library's $()$( "content" ).style.display = "none";

Example: Completely move jQuery to a new namespace in another object.

12

var dom = {};dom.query = jQuery.noConflict( true );

Result:

12345678

// Do something with the new jQuerydom.query( "div p" ).hide(); // Do something with another library's $()$( "content" ).style.display = "none"; // Do something with another version of jQueryjQuery( "div > p" ).hide();

18

Page 19: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Example: Load two versions of jQuery (not recommended). Then, restore jQuery's globally scoped variables to the first loaded jQuery.

12345678910111213141516171819202122232425262728293031

<!doctype html><html lang="en"><head> <meta charset="utf-8"> <title>jQuery.noConflict demo</title> <script src="//code.jquery.com/jquery-1.10.2.js"></script></head><body> <div id="log"> <h3>Before $.noConflict(true)</h3></div><script src="//code.jquery.com/jquery-1.6.2.js"></script> <script>var $log = $( "#log" ); $log.append( "2nd loaded jQuery version ($): " + $.fn.jquery + "<br>" ); // Restore globally scoped jQuery variables to the first version loaded// (the newer version) jq162 = jQuery.noConflict( true ); $log.append( "<h3>After $.noConflict(true)</h3>" );$log.append( "1st loaded jQuery version ($): " + $.fn.jquery + "<br>" );$log.append( "2nd loaded jQuery version (jq162): " + jq162.fn.jquery + "<br>" );</script> </body></html>

Demo:

Before $.noConflict(true)

2nd loaded jQuery version ($): 1.6.2

After $.noConflict(true)

1st loaded jQuery version ($): 1.10.22nd loaded jQuery version (jq162): 1.6.2

19

Page 20: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

Evitare conflitti con altre librerieNella creazione del nostro portale web potrebbe essere necessario utilizzare diverse librerie, magari perchè una offre dei vantaggi che l'altra non offre o più semplicemente perchè troviamo un plugin ben fatto che utilizza quella libreria piuttosto che un'altra.

Non sempre l'utilizzo contemporaneo di più librerie (o framework) differenti è ammesso, in quanto potrebbero andare in conflitto. Un problema piuttosto comune è quello che riguarda il nome dei metodi: infatti se due o più librerie implementano tramite lo stesso metodo due operazioni diverse, il sistema risulterebbe instabile e non si avrebbe certezza su quale delle operazioni viene effettivamente eseguita.

Con jQuery il problema nasce soprattutto dal fatto che molte librerie utilizzano il simbolo del dollaro come funzione o come variabile. Per questo motivo jQuery mette a disposizione la funzione noConflict() la quale esclude l'utilizzo del dollaro per jQuery "liberandolo" per altre librerie. In sostanza jQuery "rinuncia" al suo alias $().

Una premessa importante da fare prima di proseguire è la seguente: le tecniche di risoluzione dei conflitti che vedremo risolvono i problemi tra jQuery ed altre librerie che utilizzano il simbolo del dollaro, ma non tra altre due librerie che, per altri e svariati motivi, interferiscono tra loro.

Il primo sistema che viene utilizzato è quello di non utilizzare $() come alias, ma di scrivere semprejQuery(). Vediamo un esempio:

<script>jQuery.noConflict();// Usa jQuery con jQuery(...) jQuery(document).ready(function(){ jQuery("#foto").show("slow"); }); // Codice di una libreria con $(...) // ...</script>

Questo metodo può essere tuttavia poco pratico per via della riscrittura della parola "jQuery".Si può quindi decidere di cambiare l'alias di jQuery impostandone uno personale, ovviamente diverso dal dollaro. Un esempio è utilizzare "$j" invece di "jQuery". Vediamo come fare:

<script>var $j = jQuery.noConflict();// Usa jQuery con $j(...)$j(document).ready(function(){ $j("#foto").show("slow"); }); // Codice di una libreria con $(...)// ...</script>

Questo metodo è molto più rapido del precedente.Ma se non volete abbandonare il buon vecchio dollaro allora possiamo passare al terzo metodo di risoluzione dei conflitti. Mettiamo tutto il codice di interesse nella funzione ready() di fine caricamento del DOM e, al suo interno, possiamo continuare ad utilizzare jQuery come abbiamo sempre fatto:

20

Page 21: Prototype · 2013. 12. 18. · Il codice presentato è in gran parte derivato da vari altri script che meritano una abbondante esplorazione se utilizzate Prototype e siete interessati

<script>jQuery.noConflict();jQuery(document).ready(function($){ $("#foto").show("slow");});// Codice di una libreria con $(...)// ...</script>

Un ulteriore soluzione, che stavolta non prevede l'utilizzo di noConflict(), è data dall'includere la libreria jQuery prima di ogni altra libreria. In questo modo si può tranquillamente utilizzare la funzione jQuery() e lo shortcut $() il quale resta disponibile anche per le altre librerie.

<script src="jquery.js"></script><script src="prototype.js"></script><script> // Usa jQuery con jQuery(...) jQuery(document).ready(function(){ $("#foto").show("slow"); }); // Codice prototype che utilizza $(...)// ...</script>

21