Programmazione
Lato client e lato server, tutto quanto riguarda lo sviluppo e la programmazione
Programmazione
Lato client e lato server, tutto quanto riguarda lo sviluppo e la programmazione
Intanto chiedo scusa per la mia assenza, vedrò di farmi perdonare:-)
Proseguendo da dove ero rimasto l'altra volta, ho controllato un po' in giro come le librerie JavaScript più diffuse trattano l'argomento della validazione dei form. Ho visto che l'unica cosa che hanno in comune è che ognuno la fa in modo differente dagli altri...
Ad esempio qui c'è la validazione dei campi di testo secondo Spry.
Volevo però fermarmi ad analizzare come avviene la validazione nella mia libreria preferita, ovvero jQuery. Ecco un esempio di validazione con il jQuery Validation Plugin.
Guardiamo un po' il sorgente: come posso indicare che un valore in un campo è sempre richiesto ed ha lunghezza massima 2?
Argh... va be che anch'io avevo dettto che l'attributo class può essere utilizzato inserire delle annotazioni, ovvero delle informazioni "nascoste" associate ai nodi HTML, da usare poi per la validazione. Ma qui mi sembra che lo strumento venga utilizzato un po' disinvoltamente:-)
(Niente da ridire, in verità, anche io sono uno di quelli a cui piace ogni tanto sfruttare dei trucchetti..)
Però io suggerirei di inserire le annotazioni in un modo un po' diverso. Ovvero in un modo in cui nessun validatore, nessun esaminatore, nessun censore potrà mai avere a che ridire sul modo in cui queste annotazioni siano state inserite.
Ecco qua:
Ecco fatto, tutto qua. Come si vede ho inserito le informazioni direttamente all'interno di un commento posto immediatamente prima del nodo a cui si riferiscono. Inoltre in questo modo posso costruire delle annotazioni di arbitraria complessità, su qualunque nodo HTML, e naturalmente non solo per la validazione. Perché semplicemente all'interno del commento è presente un frammento di testo JSON (senza le graffe) e così potrei scrivere, ad esempio:
Qui ho specificato un campo "id" contenente un valore intero (magari letto da un database), che a questo campo sono legati in qualche modo degli altri nodi "children" (ad esempio per indicare che se uno solo di questi nodi è compilato devo compilare poi anche questo) e che associato al campo ho delle coordinate che andrò a gestire in un certo modo.
Come faccio poi via JavaScript per utilizzare questi dati "nascosti"? Con una bella funziona apposita:
Che andrò poi ad utilizzare ad esempio così:
Spesso lavorando in Javascript ci si ritrova a lavorare con i timeouts. Generare eventi temporizzati in Javascript è abbastanza banale, si ricorre all'uso di due funzioni:
Notare la sintassi dei comandi:
Ma se si devono gestire più eventi temporizzati contemporaneamente? Una possibile soluzione è creare una variabile globale in cui gestire la coda di timeout, e una funzione che ripulisca la coda.
Argomenti trattati :
# Stack
# Chiamate di procedure
# Ricorsione
Conoscenze minime :
# Un pò di C
# Concetti di programmazione
Inizio :
Come sappiamo,un programma in C per essere eseguito deve essere prima compilato,cioè tradotto in linguaggio macchina equivalente. Oggi voglio accennarvi brevemente ( per ora ) al modo in cui vengono gestite dal compilatore le chiamate di procedure,in tal modo capiremo meglio i problemi da affrontare e come sia vitale per la soluzione l'utilizzo di una struttura dati,lo stack.
Supponiamo che un a procedura Main chiami a un certo punto una procedura A1,la quale chiama a sua volta A2, la quale infine chiama A3. Possiamo schematizzare la situazione come segue :
Quando A3 termina la sua esecuzione l'istruzione che deve essere eseguita è quella,nella procedura A2, successiva alla chiamata A3 e di indirizzo t. Quando A2 termina,l'istruzione successiva deve essere quella di indirizzo s, e infine quando A1 termina va eseguita l'istruzione di indirizzo r.
I ritorni avvengono dunque in ordine inverso alle chiamate.
E' perciò importante che quando vengono chiamate le procedure gli indirizzi di ritorno vengono salvati in un recipiente da cui verranno prelevati in ordine inverso a quello di inserimento. Questo recipiente prende il nome di stack ed è una struttura dati cioè un oggetto su cui sono lecite operazioni particolari.
Uno stack viene anche detto una struttura LIFO ( Last In First Out ) in quanto l'ultimo elemento inserito nello stack è il primo ad uscire. Inizialmente lo stack è vuoto,quando la procedura Main chiama A1,l'indirizzo di ritorno r viene inserito ( push ) nello stack,quando A1 chiama A2 push dell'indirizzo s,quando A2 chiama A3 push di t. Lo stack durante l'esecuzione di A3 è il seguente :
Nel momento in cui A3 termina viene prelevato ( pop ) dallo stack l'indirizzo che sta in cima ( top ) e va in esecuzione l'istruzione di indirizzo t. Quando A2 termina,pop di nuovo e va in esecuzione l'istruzione di indirizzo s,quando termina A1,pop ancora e va in esecuzione l'istruzione r.
Ogni volta che va effettuato un return,l'indirizzo a cui tornare si trova al top dello stack.
Ora passiamo ai progammi ricorsivi. Un programma è detto ricorsivo diretto se viene chiamato all'interno del programma stesso. Un programma F1 è detto ricorsivo indiretto se chiama un programma F2,che chiama a sua volta F3,e così via,finchè Fk chiama F1. Spesso si pensa che è più semplice programmare senza la ricorsione ( infatti molti linguaggi di programmazione non la permettono ) ed è vero in MOLTI casi. Spesso però la versione ricorsiva di un programma è più compatta e facile da capire. Il motivo più importante per usare la ricorsione è che vi sono problemi che sono più facilmente risolvibili utilizzandola.
Per farvi capire meglio,vi mostrerò forse il programma ricorsivo per eccellenza : Il fattoriale.
Possiamo scrivere una semplice funzione C di fattoriale in questo modo :
per capire però bene il meccanismo di ricorsione scriviamo la funzione in modo meno compatto,utilizzando un'altra variabile. I passaggi risultano in tal modo più chiari:
ed ecco cosa succede eseguendo l'istruzione fattor=fact(3) :
Per effetto della chiamata,si entra per la prima volta nella funzione,n vale 3: poichè n non vale 1, la funzione viene chiamata una seconda volta con l'istruzione fact(n-1). Il parametro attuale vale (3-1)=2 per cui,quando entro nella funzione,n vale 2. Chiamo pertanto per la terza volta la funzione con l'istruzione fact(n-1), questa volta il parametro attuale vale (2-1) = 1. Riassumendo,le tre chiamate sono :
prima : fattor = fact(3);
seconda : k = fact(n-1) ( n vale 3 per cui (n-1)=2)
terza : k = fact(n-1) ( n vale 2 per cui (n-1)=1)
quando entro per la terza volta in fact,n vale 1 per cui esco subito dalla funzione restituendo il valore 1,torno all'ultima chiamata fatta,cioè la terza, e il valore 1 viene assegnato a k. Nel contempo,n automaticamente riassume il valore che aveva all'atto della terza chiamata(2).
Va quindi in esecuzione l'istruzione return n*k e viene restituito il valore 2*1=2. Si torna ora all'ultima chiamata fatta,cioè la seconda,k assume il valore 2 e n automaticamente riassume il valore 3. Va ora in esecuzione return n*k e viene restituito il valore 3*2=6. Si torna all'ultima chiamata fatta,questa volta è la prima,fattor = fact(3),e il valore 6 viene assegnato a fattor.
Vi ho mostrato la gestione delle chiamate di procedure mediante stack. Nel momento in cui abbiamo programmi ricorsivi le cose si complicano grandemente : infatti all'atto della chiamata ricorsiva oltre all'indirizzo di ritorno vanno salvati tutti i valori dei parametri in quel momento,e tali valori ripristinati al momento del return.
Per questo,anche se a volte sembra che ci " convenga " usare la ricorsione,dobbiamo stare attenti.
Programmi ricorsivi complessi richiedono il salvataggio di tutto un set di parametri per un numero di volte che dipende dal numero di livelli di ricorsione,questo complica molto il lavoro del compilatore per cui molti linguaggi di programmazione,come già detto,hanno " risolto " il problema alla radice non consentendo l'uso della ricorsione.
Questo è solo una prima parte,alla prossima,ciao !
E' forse un argomento marginale per il Laboratorio Caffeina, ma cosa fare quando i nostri occhi sulla rete cominciano ad appannarsi o smettono completamente di vedere?
Ovvero, quando quei complessi programmoni chiamati "browser" si piantano impietosamente. Si da la colpa al browser? Al sito web "mal progettato"? Forse, ma prima è bene stracciare tutto il possibile...
Ormai un mesetto fa Repubblica.it ha cominciato a provocare improvvisi crash di Iceweasel/Firefox. Ecco l'ordine in cui NON bisognerebbe procedere in questi casi:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1222601024 (LWP 17712)]
0x08384ced in nsTextFrame::Reflow (this=0x98a22d0, aPresContext=0x92e3688, aMetrics=@0xbfbb52d4, aReflowState=@0xbfbb521c,
aStatus=@0xbfbb5388) at nsTextFrame.cpp:594
594 nsTextFrame.cpp: No such file or directory.
in nsTextFrame.cppverrà avviato iceweasel mentre lo standard out viene inondato di informazioni. Ogni riga dell'output specifica quale chiamata di sistema sta venendo inoltrata dal programma lanciato, in quel preciso istante. Nel mio caso il debug è stato molto semplice: quando iceweasel è uscito inaspettatamente, sono andato a leggere quali chiamate erano in corso.
[...]
open("/var/lib/defoma/fontconfig.d/L/LucidaSans.ttf", O_RDONLY) = -1 ENOENT (No
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
unlink("/home/daniele/.mozilla/firefox/kl5cndvj.default/lock") = 0
rt_sigaction(SIGSEGV, {SIG_DFL}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [SEGV], NULL, 8) = 0
tgkill(3367, 3367, SIGSEGV) = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Process 3367 detached
Come lasicava pensare il messaggio di debug "No such file or directory.", Iceweasel stava tentando di aprire un file senza riuscirvi: l'ultima chiamata di sistema prima del segnale SIGSEGV è un open(), cioè più o meno "accedi ad un file o ad una periferica". Dagli argomenti della chiamata possiamo capire quale file Iceweasel stava aprendo, in che modalità (lettura, scrittura, etc), ed il codice d'uscita accompagnato da altre informazioni.
| open( | Nome della chiamata di sistema (apri file o periferica) |
| "/var/lib/defoma/fontconfig.d/L/LucidaSans.ttf", | Arg.1: Percorso del file da aprire |
| O_RDONLY ) | Arg.2: Modalità d'accesso: sola lettura |
| = -1 ENOENT (No | Codice d'uscita: No such file or directory (troncato da strace) |
Ora non resta che da capire cosa non va con questo benedetto file: var/lib/defoma/fontconfig.d/L/LucidaSans.ttf !
Listando la cartella in cui si trova, vedo che, assieme a tanti altri, si tratta di un link simbolico interrotto:
$ ls -l /var/lib/defoma/fontconfig.d/L
[...]
lrwxrwxrwx 1 root root 58 2007-05-02 10:59 LucidaSans.ttf -> /usr/share/fonts/truetype/ttf-lucida/LucidaSansRegular.ttf
[...]
E listando la cartella /usr/share/fonts/truetype/ttf-lucida mi accorgo che anche LucidaSansRegular.ttf è un link interrotto:
$ ls -l /usr/share/fonts/truetype/ttf-lucida
[...]
lrwxrwxrwx 1 root root 81 2007-02-16 01:13 LucidaBrightRegular.ttf -> ../../../../lib/jvm/java-1.5.0-sun-1.5.0.11/jre/lib/fonts/LucidaBrightRegular.ttf
[...]
E la catena di link interrotti è giunta a conclusione: il problema è che la cartella /lib/jvm non esiste! Quindi tutti i link risultano interrotti e quando Iceweasel tenta di aprire l'inizio della catena, si trova con un errore fatale.
E' fuori discussione che il link si riferisca a Java (java-1.5.0-sun-1.5.0.11 nel percorso), quindi qualcosa deve esser andato storto con la mia installazione di Java... Sono su Debian, quindi la soluzione più rapida al problema è senza dubbio reinstallare il pacchetto di sun-java6-fonts.
Due minuti dopo stavo navigando su Repubblica...
E la sequenza giusta? Quella inversa, naturalmente.
Col senno di poi...
Ok, second chance to me, after the Restrict authors access to edit comments plugin I did the second one.
I think that the name is quite explicative: I wanted to add the wysiwyg to the user description .
INSTRUCTION:
download v.0.1 and copy the file into wp-content/plugins.
activate it.
Now you should see in the edit user details the wysiwyg editor.
You can manage to modify TinyMCE script, following instruction
Hope you like it
tested on wordpress 2.2
IN ORDER TO LET IT WORK IN 2.5
replace this part of code:
with this:
It's my first wordpress plugin, please be kind ;-)
I've noticed that in wordpress (surely 2.2, not tested on previous, so please tell me if it works) there's no capability separation for editing post and comments (on their post). Even using the Role Manager Plugin.
from wordpress codex:
Manage->Comments -- meaning: "show post"-link; "edit post"-, "edit comment"- and "delete comment"-links only on own posts since edit-comment.php (http://trac.wordpress.org/file/trunk/wp-admin/edit-comments.php) looks for "current_user_can('edit_post', $comment->comment_post_ID)"'
I run a lot of multiple authors blogs and sometimes I need only administrators to edit comments (and I'm not the only one).
So I developed this:
update
thanks to brad I found out that the direct edit comment link in wordpress points to comments.php and not to edit-comments.php.
so I've changed the script.
update 2
Thanks to Fred (sorry I didn't understand immediatly) and Claus I spotted out another error in version 0.2
Now I've done the v.0.3 changing the hook function: now it works not on the content but on the initialization of the page, so it is not possible for the author to work on comments at all. thanks to everyone :-)
simply download v.0.3, unzip, put the .php file under wp-contents/plugins and activate it from wordpress plugins panel.
Sto arrovellandomi per trovare, tra le tante soluzioni, quale sia la più elegante per risolvere il problema della validazione dei form.
Il problema è sempre lo stesso. Come indicare che un campo è obbligatorio, oppure deve contenere un numero intero, oppure una textarea deve avere al massimo un certo numero di caratteri?
Be' se fossimo in un mondo perfetto la soluzione ci sarebbe già, e si chiamerebbe HTML 5. Guardate ad esempio cosa hanno pensato bene quelli del WHATWG nella specifica Web Forms 2.0 sull'argomento validazione. Però in un mondo perfetto non siamo...
Ad esempio per specificare un campo obbligatorio cosa c'è di meglio di un attributo "required"? Poi basterebbe l'utilizzo di una semplice funzione JavaScript per controllarne la correttezza, come descritto per esempio nell'articolo JavaScript triggers di Peter-Paul Koch.
E allora il problema qual'è? La soluzione sembra già a portata di mano. Ebbene il problema è il seguente: la specifica HTML attuale, con l'ausilio dei famigerati DTD HTML, non permettono l'introduzione di attributi "alieni" all'interno di un elemento HTML.
Questo si guardi bene potrebbe essere contestato. Che fastidio potrebbe dare un attributo in più se gli attributi necessari fossero già presenti? Semplicemente il browser che non ne capisca il significato potrebbe scartare l'attributo, come già fanno adesso tutti i browser creati fino a questo momento!
Però il problema rimane. Una buona soluzione deve funzionare anche in caso di necessità di validazione HTML. Bisognerebbe trovare una soluzione di classe... che dico di classe, di "class"!
Vediamo come potremmo fare:
Vi sembra brutto? Voi mi direte: l'attributo "class" serve ad altro, non è corretto utilizzarlo in questo modo. E invece io dico: cosa vuol dire "appartenere ad una classe"? Non significa che questa classe debba avere soltanto delle implicazioni sul modo in cui l'elemento viene visualizzato. Anzi è consigliato che il nome della classe ne sappresenti il significato e non l'aspetto. Ad esempio classe "errore" e non classe "rosso", perché magari un errore sarà sempre mostrato in rosso ma la classe ne deve indicare il significato e non l'aspetto, che devono rimanere indipendenti.
E qui volevo arrivare! Utilizzare una classe per indicare una caratteristica strutturale dell'elemento non va in conflitto con il fatto di specificare come quell'elemento deve essere visualizzato. Ad esempio io potrei volere che tutti i campi obbligatori abbiamo lo sfondo giallo, mentre tutti i campi interi abbiano un bordo rosso:
E nello stesso tempo una funzione JavaScript potrebbe controllarne la validazione:
Si veda bene che questo codice non vuol essere lo script migliore che si possa scrivere per gestire la validazione di un campo, ma solo un esempio su come semplice possa essere l'utilizzo di questo sistema. E le soluzione più semplici (a volte) sono le migliori:-) Questa come vi pare?
Naturalmente questo è solo l'inizio...