Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

MooTools: creare un plugin

Impariamo a estendere le funzionalità offerte da MooTools
Impariamo a estendere le funzionalità offerte da MooTools
Link copiato negli appunti

Dopo avere accuratamente analizzato tutti i più importanti plugin ufficiali offerti dal framework MooTools nei precedenti articoli, è arrivato il momento di vedere come è possibile realizzare la propria estensione personalizzata. In questo tutorial, infatti, non impareremo ad usare alcun componente ufficiale, ma vedremo come sfruttare le API offerte da MooTools per creare un plugin personale partendo da zero e analizzando tutte le fasi che compongono il percorso necessario alla realizzazione.

Ovviamente, il procedimento che porta alla creazione di un plugin è una fase più avanzata e complessa rispetto all'utilizzo dei componenti offerti nativamente, poiché con essa subentrano parecchi prerequisiti, tra i quali vi sono la buona conoscenza del costruttore Class, delle Class Extras e delle teorie della OOP (programmazione a oggetti).

Per un'accurata analisi dei costruttori Class e delle Class Extras (Chain, Events ed Options) vi rimando alle rispettive lezioni della guida dedicata alla versione 1.2 di MooTools:

Per quanto riguarda le teorie della OOP, riporto di seguito un semplice e veloce ripasso dei concetti utili ai fini del tutorial.

Teorie

Modularità e gerarchie

Uno dei vantaggi fondamentali offerti da una struttura Object-Oriented è la modularità dell'applicazione. I nostri plugin dovranno essere sempre il più possibile modulari:

plugin A estende MooTools	script1.js
plugin B estende plugin A	script2.js

Ad esempio, supponiamo che il plugin A estenda una classe di effetti offerta nativamente da MooTools e che uno degli scopi del plugin B sia quello di creare animazioni aggiuntive e complementari. Sarà opportuno fare in modo che B e A condividano le stesse funzionalità e facciano parte della stessa gerarchia (invece che creare un plugin B completamente nuovo): in questo modo si ridurranno notevolmente i KB e avremo un codice molto più mantenibile in caso di modifiche o aggiunte future.

Estendere, superclassi e sottoclassi

Quando una classe estende un'altra classe, essa eredita tutte le sue funzionalità. L'estensione permette dunque di creare plugin basati su qualsiasi classe offerta nativamente da MooTools (come ad esempio Fx.Tween, Slider e cosi via...), che a loro volta possono essere ulteriormente estesi.

Si dice superclasse la classe che viene "estesa" e che dunque "offre" le proprie funzionalità ad altre classi. Una sottoclasse è invece la classe che "eredita" dalla superclasse.

Costruttori e istanze

Un costruttore, come indica la parola, è la classe che permette di creare le istanze del nostro plugin che poi potranno essere utilizzate dall'utente finale. Di solito si usa il nome della classe unito all'operatore new: il metodo costruttore initialize verrà richiamato all'inizializzazione dell'istanza come vedremo successivamente. Ecco un esempio:

var fx = new Fx.Tween('myElement', myOpts);

Fx.Tween è il costruttore (o classe) mentre la variabile fx rappresenta un'istanza della classe Fx.Tween. Se non si implementano particolari Design Pattern, questa sarà l'unica modalità disponibile per creare istanze.

Implementare

Nella OOP, quando una classe implementa un'interfaccia, essa si impegna a ridefinire tutti i metodi di questa interfaccia per ottenere una API comune a tutte le classi della gerarchia. In realtà MooTools definisce un concetto leggermente diverso di "implementazione", come vedremo tra qualche paragrafo.

Pratiche

Ora che abbiamo rispolverato i concetti utili alla creazione del nostro plugin è ora di passare all'analisi della fase successiva, in cui possiamo metterli in pratica avvalendoci delle API di MooTools.

Estendere, superclassi e sottoclassi

Come abbiamo imparato dalla guida, per estendere una classe di tipo Class dobbiamo utilizzare la proprietà Extends ed indicare il costruttore che si intende estendere:

var A = new Class({

	/* collezione di metodi e proprietà di A */

});

var B = new Class({

	Extends: A,
	
	/* collezione di metodi e proprietà di B */

});

Questo snippet asserisce che la classe B guadagna tutti i metodi e tutte le proprietà della classe A. Se quest'ultima possiede ad esempio un metodo chiamato sayIt, anche la classe B disporrà di tale metodo.

Ovviamente, dato che Javascript non è un linguaggio OOP "puro", non sono disponibili molti degli accessori tipici di un linguaggio completamente Object-Oriented, ma la particolare struttura di MooTools permette di emularli piuttosto bene. Ad esempio, per accedere al metodo sayIt della classe A, accennato in precedenza, nella classe B, si può usare la proprietà parent che richiama qualsiasi metodo della classe parente avente uguale nome:

var A = new Class({

	/* collezione di metodi e proprietà di A */

	sayIt: function() {
		alert("You said it!");
	}

});

var B = new Class({

	Extends: A,
	
	/* collezione di metodi e proprietà di B */
	
	sayIt: function() {
		this.parent();
		alert("You said it again, from B!");
	}

});

In questo modo è possibile simulare il concetto di superclassi e sottoclassi. Se infatti creiamo un'istanza di B e richiamiamo il metodo sayIt, il risultato sarà un doppio alert, uno proveniente dal metodo della superclasse A con il messaggio "You said it!" ed uno con il testo "You said it again, from B!":

var objB = new B;

b.sayIt();

Costruttori e istanze

Se implementiamo un metodo chiamato initialize all'interno della nostra classe, esso svolgerà il ruolo di costruttore. È spesso utilizzato per specificare i parametri delle nostre istanze, come ad esempio l'oggetto options che stabilisce le opzioni che alterano il comportamento della nostra classe (vedi la lezione Integrazione con le Class Extras):

var A = new Class({

	initialize: function(name, country) {
		this.name = name;
		this.country = country;
	},

	/* collezione di metodi e proprietà di A */

});

var objA = new A('George', 'United Kingdom');

Implementare

Con la proprietà Implements possiamo appunto implementare una serie di metodi all'interno della nostra classe. Come detto in precedenza, il concetto di implementazione definito da MooTools è leggermente differente da quello definito dalla OOP standard.

In pratica, quando si implementano nuovi metodi con MooTools, si "assumono" effettivamente questi metodi. Per questo motivo, le classi che vengono create appositamente per essere implementate, molto difficilmente verranno usate direttamente dall'utente. Alcune delle classi che vengono implementate frequentemente sono Chain, Events ed Options. Vediamo un'esempio di implementazione:

var A = new Class({

	Implements: [Options],
	
	options: {
		autoCancel: true;
		effects: ['fade', 'scroll'],
		cookie: false,
		info: 'some info'
	},

	initialize: function(name, country, options) {
		this.name = name;
		this.country = country;
		this.setOptions(options);
	},

	/* collezione di metodi e proprietà di A */

});

Si conclude qui la sezione 'teorica'. Vedremo nella seconda parte come creare una semplice estensione applicando i concetti fin qui appresi.

Creazione

Ora che abbiamo analizzato tutte le meccaniche di cui possiamo avvalerci per la creazione del nostro plugin e le teorie che stanno alla loro base, è ora di passare alla fase finale: la creazione definitiva.

Il plugin che andremo a realizzare permetterà di gestire un elemento DOM della nostra pagina creando una sorta di "wrapper". Esso consentirà di modificare e aggiornare l'elemento in tempo reale diminuendo la quantità di codice da scrivere normalmente necessaria. Premetto che, alcune delle funzionalità presenti in questo script possono essere facilmente realizzate tramite una semplice estensione del costruttore Element, ma per il nostro tutorial una struttura gerarchica e modulare è l'obiettivo ultimo.

Il plugin sarà composto da due classi separate: una superclasse chiamata CustomBase e una classe che la estende denominata CustomSuper. La classe CustomBase avrà i seguenti metodi pubblici:

  • changeBg: permette di cambiare il colore dello sfondo di un elemento;
  • changeFg: permette di cambiare il colore di primo piano di un elemento;
  • update: aggiorna il contenuto di un elemento;
  • hide: nasconde l'elemento;
  • show: mostra l'elemento.

Ecco la sua struttura:

var CustomBase = new Class({

	// metodo costruttore
	initialize: function(element) {
		this.element = $(element);
		return this;
	},
	
	// metodi pubblici
	changeBg: function(color) {
		this.element.setStyle('background-color', color);
		return this;
	},
	
	changeFg: function(color) {
		this.element.setStyle('color', color);
		return this;
	},
	
	update: function(html) {
		this.element.set('html', html);
		return this;
	},
	
	hide: function() {
		this.display = this.element.getStyle('display');
		this.element.setStyle('display', 'none');
		return this;
	},
	
	show: function() {
		this.element.setStyle('display', this.display);
		return this;
	}

});

Una volta definita la struttura del plugin, è poi possibile passare alla creazione delle istanze:

window.addEvent('domready', function() {

	var el1 = new CustomBase('el1');
	
	el1.changeBg('blue')
	   .changeFg('white').
	   .update('New Text');

});

L'elemento con id 'el1' assumerà un colore di sfondo "blue", un colore di primo piano "white" e avrà come nuovo contenuto il testo "New Text". Nota importante: è molto elegante e usabile restituire la corrente istanza in ogni metodo che non ha un valore restituito definito: in questo modo sarà possibile concatenare più chiamate contemporaneamente.

Con la classe CustomSuper, il nostro plugin guadagna molte più caratteristiche. Ecco le nuove funzionalità dei metodi pubblici ridefiniti:

  • update: aggiorna il contenuto di un elemento se si passa una stringa, se si passa un oggetto vengono settate le proprietà dell'elemento;
  • hide: nasconde l'elemento. Se si passa true viene nascosto con un'animazione;
  • show: mostra l'elemento. Se si passa true viene mostrato con un'animazione.

Inoltre, la classe CustomSuper implementa il costruttore Options: sarà cosi possibile settare la durata delle animazioni interne. Ecco la sua struttura completa:

var CustomSuper = new Class({

	options: {
		duration: 2000
	},

	Extends: CustomBase,
	
	Implements: [Options],

	initialize: function(element, options) {
		this.parent(element);
		this.setOptions(options);
		this.element.set('morph', {link: 'chain', duration: this.options.duration});
		return this;
	},
	
	update: function(html) {
		($type(html) == 'object') ? this.element.setProperties(html) : this.parent(html);
		return this;
	},
	
	hide: function(fx) {
		this.height = this.element.getStyle('height');
		(fx) ? this.element.morph({height: 0}) : this.parent();
		return this;
	},
	
	show: function(fx) {
		(fx) ? this.element.morph({height: this.height}) : this.parent();
		return this;
	}

});

Anche in questo caso, possiamo passare alla creazione delle istanze:

window.addEvent('domready', function() {

	var el2 = new CustomSuper('el2');
	   
	 el2.update({class: 'new_class'})
	 	.hide(true)
		.show(true);

});

In questo secondo gradino della gerarchia abbiamo ampliato notevolmente le funzionalità della classe base, senza l'occorrenza di riscrivere le parti già definite in precedenza: modularità in primo piano.

Potete trovare tutto il codice dell'applicazione, completo di HTML, in questa demo. Ecco inoltre il link per scaricare il pacchetto completo contenente file HTML, MooTools e lo script inline del nostro plugin.

Conclusione

Come abbiamo potuto vedere, tramite MooTools possiamo creare vere e proprie gerarchie di classi molto simili a quelle realizzabili con le teorie della OOP originale, ma avvalendoci del linguaggio Javascript. Questo ci consente di creare plugin collegati tra loro che condividono risorse e funzionalità.

Ovviamente la complessità delle gerarchie dipende fortemente dal progetto e dal proprio obiettivo finale. Quello che è fondamentale capire sono i mezzi e le teorie che il framework ci mette a disposizione e le metodologie per sfruttarle al meglio. In questo tutorial sono racchiusi tutti questi concetti.

Ti consigliamo anche