javascript, jquery, tutorial

Autocomplete con jQuery

09.14.09 | 21 Comments

NB: ci sono novità al fondo del post

Pubblico le mie 3 implementazioni del plugin jQuery Autocomplete di Jörn Zaefferer.

Queste implementazioni servono ad attivare campi form con suggest automatico senza scrivere una sola riga di javascript.

La prima implementazione autoattiva il plugin originale (con supporto ai metadata):

La seconda implementazione aggiunge “magicamente” un campo “hidden” e in fase di invio del “form” spedisce al server anche la chiave associata al valore selezionato nel suggest.

La terza invece crea un suggest “tabellare”. E’ stato necessario modificare lo script.

Per le demo ho usato:

HEAD HTML

Includere le librerie e i css necessari.


	<link href="lib/jquery.autocomplete.css" rel="stylesheet" type="text/css" media="screen" />
	<script src="lib/jquery-1.3.2.min.js" type="text/javascript"></script>
    <script src="lib/jquery.metadata.js" type="text/javascript"></script>
    <script src="lib/jquery.autocomplete.js" type="text/javascript"></script>
	<script src="autocomplete.custom.js" type="text/javascript"></script>

DOWNLOAD DEMO

SUGGEST BASE

Per attivare un suggest base è sufficiente

  • assegnare al campo input la classe suggest.
  • valorizzare l’attributo alt del campo input inserendo un url relativo es: “php/mesi.php”

Lo script php d’esempio che restituisce alle chiamate ajax l’elenco dei valori:


$q = strtolower($_GET["q"]);
if (!$q) return;
$items = array(
	'gennaio',
	'febbraio',
	'marzo',
	'aprile',
	'maggio',
	'giugno',
	'luglio',
	'agosto',
	'settembre',
	'ottobre',
	'novembre',
	'dicembre'
);

foreach ($items as $value) {
    if (strpos(strtolower($value), $q) !== false) {
        echo "$value\n";
    }
}

Chiaramente nelle applicazioni reali i dati non verranno presi da un array ma da un database

ESEMPIO 1


<input type="text" name="suggest1" id="suggest1" class="suggest" alt="php/mesi.php" />

ESEMPIO 2

Grazie all’uso di jQuery metadata le opzioni dell’autocomplete possono essere settate direttamente nell’html (quindi senza scrivere codice javascript).
L’elenco delle opzioni che modificano il comportamento del plugin si trova qui.


<input type="text" name="suggest2" id="suggest2" class="suggest {multiple:true}" alt="php/mesi.php" />

ESEMPIO 3


<input type="text" name="suggest3" id="suggest3" class="suggest {minChars:3, max:3}" alt="php/search.php" />

SUGGEST CHIAVE VALORE

La seconda implementazione di jQuery Autocomplete crea un campo hidden per la chiave legata al valore visualizzato in suggest in modo da poter inviare al server sia la chiave sia il valore in fase di submit.

Per attivare un suggest chiave/valore è sufficiente

  • assegnare al campo input la classe suggest_keys.
  • valorizzare l’attributo alt del campo input inserendo un url relativo es: “php/keys.php”

Lo script php d’esempio che restituisce alle chiamate ajax l’elenco di chiavi|valori:


$q = strtolower($_GET["q"]);
if (!$q) return;
$items = array(
	"10024" => "Moncalieri",
	"20000" => "Monza",
	"10100"	=> "Torino"
);

foreach ($items as $key=>$value) {
    if (strpos(strtolower($value), $q) !== false) {
        echo "$key|$value\n";
    }
}

ESEMPIO 4


<input type="text" name="suggest4" id="suggest4" class="suggest_keys" alt="php/keys.php" />

Se utilizzate firebug potrete vedere che viene creato un campo nascosto. Es:


<input type="hidden" value="" id="suggest4_hidden" name="suggest4_hidden"/>

ESEMPIO 5


<input type="text" name="entita[campo]" id="entita_campo" class="suggest_keys" alt="php/keys.php" />

Se utilizzate firebug potrete vedere che viene creato un campo nascosto. Es:


<input type="hidden" value="" id="entita_campo_hidden" name="entita[campo_hidden]"/>

SUGGEST TABELLARE

La terza implementazione di jQuery Autocomplete è un po’ più complessa e prevede l’utilizzo di una versione modificata di jquery autocomplete.

Per attivare un suggest tabellare è sufficiente

  • Includere nell’head la versione modificata di jQuery Autocomplete
  • assegnare al campo input la classe suggest_table.
  • personalizzare le intestazioni di colonna nell’attributo class (vedi sotto l’esempio)
  • valorizzare l’attributo alt del campo input inserendo un url relativo es: “php/table.php”
  • Includere le seguenti istruzioni css personalizzando “le larghezze” che nell’esempio settano le 3 colonne della tabella

.ac_results ul li div.tbl{clear:both;}
.ac_results ul li div.tbl div{float:left;width:30%;overflow-x:hidden;}
.ac_intestazione{position:absolute;left:0px;top:-0px;z-index:1000;background:#000;color:#fff;}

/*PERSONALIZZA*/
.ac_results ul li div.tbl div.fld_1, #int_1{width:150px;}
.ac_results ul li div.tbl div.fld_2, #int_2{width:70px;}
.ac_results ul li div.tbl div.fld_3, #int_3{width:70px;}

Lo script php d’esempio che restituisce alle chiamate ajax l’elenco dei valori della tabella.


$q = strtolower($_GET["q"]);
if (!$q) return;
$items = array(
	"10024" => array(
		"Moncalieri",
		"Torino",
		"Piemonte"
	),
	"20000" => array(
		"Conegliano",
		"Treviso",
		"Veneto"
	),
	"10100"	=> array(
		"Alba",
		"Cuneo",
		"Piemonte"
	)
);

foreach ($items as $key=>$array) {
	$str = join($array,"#");
    if (strpos(strtolower($str), $q) !== false) {
        echo "$key|$str\n";
    }
}

ESEMPIO TABELLARE


<input type="text" id="suggest1" name="suggest1" class="suggest_table {th : ['città', 'provincia', 'regione']}" alt="php/table.php" style="width:300px;" />

AGGIORNAMENTO 13-11-2009:

Ho aggiornato lo ZIP con le demo e gli script di questo post.

Ho aggiornato in particolare

Ho aggiunto questa DEMO per il passaggio delle opzioni autocomplete al plugin base (jquery.autocomplete.mod.js).

Le porzioni di jquery.autocomplete.js modificate sono a questo punto due, entrambe nel metodo/funzione fillList:


var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
//PATCH
if(i == 0 && $(input).is(".suggest_table")){
	$(li).addClass("ac_first");
	var _ie_sucks = typeof document.body.style.maxHeight === "undefined" || //IE6
					(document.all && !window.opera && window.XMLHttpRequest); //IE7
	if (_ie_sucks || max == 1) {
		$(li).attr("style", "padding-top:20px");
	}
}
//PATCH
$.data(li, "ac_data", data[i]);

listItems = list.find("li");
if ( options.selectFirst ) {
	//PATCH
	//listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
	listItems.slice(1, 2).addClass(CLASSES.ACTIVE);
	//PATCH
	active = 0;
}

Per questa seconda modifica, ringrazio Mansportivo che nei commenti qui sotto mi ha segnalato l’anomalia.

Popularity: 58% [?]

javascript, jquery, plugins

Ahah & unobtrusive javascript

07.27.09 | 8 Comments

DEMO

IL PROBLEMA

Javascript non intrusivo ha un problema di fondo.
Lavorando sull’evento window.onload, i componenti javascript non intrusivi, NON si attivano nel momento in cui viene fatta un’ iniezione html nel DOM (AHAH).

Qui ho scritto un banale esempio.

Il plugin aggiunge le funzionalità draggable e resizable (jQuery UI) agli elementi HTML selezionati.

Il plugin come “comportamento di default” agisce su tutti gli elementi con classe “box” :


$(document).ready(function(){
	$(".box").myplugin();
});

Quindi nella demo tutti gli elementi con classe “box” saranno draggabili e ridimensionabili.

Il link ADD, nella DEMO, aggiunge elementi box via ajax (AHAH):


$("#add").click(function(){
    $.ajax({
        url     : 'box.html',
        success : function(html){
            $("body").append($(html).myplugin());
        }
    });
});

Questi elementi arrivando da un iniezione HTML non vengono “arricchiti” dal plugin (non sono quindi ridimensionabili ne trascinabili) perchè non sono presenti al window.onload (al document.ready per chi usa jquery).

Questo problema non si avvertirebbe se il componente fosse intrusivo (js cablato nell’html):


<div id="box1"></div>
<script type="text/javascript">
//<![CDATA[
$("#box1").myplugin();
//]]>
</script>

Se io iniettassi il codice qui sopra il box si attiverebbe perchè verrebbe valutato il js (almeno se iniettato via jquery) immediatamente senza eventi onload di mezzo.

Spesso i framework server-side sono intrusivi proprio per essere più flessibili.
Il codice html generato sarà sporco (richfaces ad esempio) ma i componenti saranno sempre “funzionanti” sia al primo caricamento sia a seguito di iniezioni html.

SOLUZIONE MANUALE

La soluzione “manuale” (a carico dello sviluppatore che implementa il comportamento e USA il plugin) è attivare le funzionalità js prima di appendere il nuovo pezzo di html. DEMO


$("#add").click(function(){
    $.ajax({
        url     : 'box.html',
        success : function(html){
            $("body").append($(html).myplugin());
        }
    });
});

Questa è la soluzione che più di frequente utilizzo.

Se invece avessi scritto il plugin ecco come potrei fare (quindi spostando la responsabilità al plugin stesso).

SOLUZIONE AUTOMATICA

L’idea è : quello che attivo al document.ready lo attivo anche all’evento ajaxStop (quindi inizializzo il plugin sia al window.onload sia alla chiusura di ogni chiamata ajax).


$(document)
.ready(function(){
    $(".box").myplugin();
})
.ajaxStop(function(){
    $(".box").myplugin();
});

Il problema di questa soluzione è che applicando 2 volte ad un elemento lo stesso plugin si “rischia” spesso di ottenere degli effetti indesiderati (doppi eventi al click, interfaccia che si moltiplica a mo’ di matrioska, ecc…).

La soluzione quindi è realizzare un qualche sistema di singleton all’elemento che si arrichisce.
Nel plugin finale ho scritto un banale if che aggiunge una certa classe (flag) all’elemento arricchito.
Se un evento (ajaxStop) invoca il costruttore del plugin più volte il codice non verrà eseguito.


//singleton
if ($(that).is(".myplugin")) {
   return;
} else {
   $(that).addClass(".myplugin");
}
//plugin code...

Popularity: 5% [?]

dokuwiki

Dokumu – Dokuwiki multiutente

07.13.09 | Comment?

Pubblico le istruzioni per ottenere un dokuwiki multiutente.

QUESTA E’ SOLO UNA BOZZA.

PREREQUISITI :

a) capire il post
b) avere un apache su cui provare la patch/estensione*
c) mod_rewrite

*ho provato il tutto velocemente su uno xampp (apache su windows). NON FUNZIONA.

Non c’è ancora nessun batch/plugin/script che esegua automaticamente la creazione di un istanza wiki.

lo scopo della patch è arrivare ad avere una serie di wiki con repository dati separate.

http://localhost/wiki/base/

http://localhost/wiki/max/

http://localhost/wiki/carlo/

etc….

Scarico l’ultima versione stabile di dokuwiki

dokuwiki-2009-02-14b.tgz

Scarico la patch/estensione dokumu

dokumu-2009-02-14b.tar.gz

Estraggo nella ROOT (htdocs) di apache dokumu

step3

Estraggo in una directory temporanea dokuwiki

a) COPIO LE DIRECTORY

/data
/conf

in /repository/wiki/istances/base/ rispondendo si quando chiede di sovrascrivere/unire le directory.

b) COPIO LE DIRECTORY e i FILES restanti (bin, inc, lib, doku.php etc)

in /wiki (sotto htdocs NON in /repository/wiki !)

Ecco l’albero risultante dal merge di dokuwiki con quest’estensione “dokumu”

step4b

Setto i permessi di scrittura alla directory

/repository e figli

Modifiche DOKUWIKI – /wiki/inc/init.php

inserisco questa riga subito dopo l’apertura del tag php (<?php)


require_once(dirname(__FILE__).'/../extensions/istances/config.php');

Lancio Dokumu

http://localhost/wiki/base/

dove localhost è l’indirizzo a cui risponde il vostro web server

Creazione Istanza

L’istanza è automaticamente creata lanciando sul browser l’url di partenza seguito dal nome dell’istanza

http://localhost/wiki/NOME_ISTANZA/

Se:

1) ho creato la directory

/repository/wiki/istances/NOME_ISTANZA

2) ho copiato le directory

/data
/conf

presenti nel dokuwiki-2009-02-14b.tgz

3) nella directory

/repository/wiki/istances/NOME_ISTANZA/conf/

ho creato local.php (vedi dentro dokumu-2009-02-14b.tar.gz)

con dentro ALMENO questo valore impostato

$conf['savedir'] = DATA_PATH;

4) liberi di settare i files

local.php
acl.auth.php
users.auth.php

NON HO TESTATO LA PATCH CON
$conf['userewrite']  = 1;

Popularity: 2% [?]

varie, video

Fichissimi

06.16.09 | 1 Comment

min 3:30 – il sorpasso più spettacolare che io ricordi

1-il-momento

2-in-piega

sorpasso

tre

Popularity: 1% [?]

javascript, jquery, plugins

comodoclick

05.12.09 | 2 Comments

LINKS:

FUNZIONALITA’:

  • Aggiunge la classe “hover” ai td di una certa riga di tabella (tr > td) sull’evento hover del tr
  • Aggiunge la classe “selected” ai td di una certa riga di tabella (tr > td) sull’evento click del td
  • Aggiunge la classe “selected” ai td di una certa riga di tabella al click sui controlli form checkbox e radio (di conseguenza anche al click sulle label) presenti sulla riga stessa
  • Nel caso di input:radio la classe selected viene prima cancellata dalle altre righe e poi applicata alla riga “selezionata”

AUTOLOAD

Per attivarlo basta includere gli scripts (jquery, comodoclick) e aggiungere la classe comodoclick ad una tabella.


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

<table class="comodoclick">

CSS

Personalizzare a piacere queste classi css:


table.comodoclick tr td.hover {background-color:red;}
table.comodoclick tr td.selected {background-color:green;}

CODE

Il plugin con qualche nota:


/*
 * Copyright (c) 2008 Massimiliano Balestrieri
 *
 * @requires jQuery v1.3.2
 *
 * Copyright (c) 2008 Massimiliano Balestrieri
 * Examples and docs at: http://maxb.net/blog/
 * Licensed GPL licenses:
 * http://www.gnu.org/licenses/gpl.html
 */
;
(function($){

    function ComodoClick(){
        return this.each(function(){
            var that = this;

            jQuery("tr", this).hover(function(){
                jQuery("td", this).addClass("hover");
            }, function(){
                jQuery("td", this).removeClass("hover");
            });

            jQuery("tr", this).click(function(e){
                var _target = e.target || e.srcElement;
                var _tag = _target.tagName.toString().toLowerCase();
                //prendo solo il click sul td
                //se ci fossero tag di tipo blocco dentro il td sarebbe un problema
                //se invece clicco su una input o su una label gestisco tutto con l'evento -> VEDI SOTTO
                if (_tag === 'td') {
                    var _tr = jQuery(this);
                    _highlight_row(_tr, true);
                }
                //return false;
            });

            //vedi sotto A
            jQuery("tr", this).find("input:checkbox, input:radio").bind("click", function(){
                var _tr = jQuery(this).parents("tr");
                _highlight_row(_tr, true);
            });
            //vedi sotto B
            jQuery("tr", this).find("input:checkbox").bind("checked", function(){
                var _tr = jQuery(this).parents("tr");
                _highlight_row(_tr, false);
            });

            var _highlight_row = function(_tr, flag){
                //il flag è per selezionare la checkbox/radio forzatamente
                //checkbox gestisce la "multiselezione"

                var _checkbox = jQuery("input:checkbox", _tr).length > 0;

                //nel caso dei radio cancello le altre colorazioni
                if (!_checkbox) {
                    jQuery("td", that).removeClass("selected");
                    jQuery("tr", that).removeClass("selected");
                    jQuery("td", _tr).addClass("selected");
                    _tr.addClass("selected");

                    if (flag) {
                        jQuery("input:radio", _tr).attr("checked", "checked");
                    }

                }
                else {
                    var _selected = _tr.is(".selected");
                    if (_selected) {
                        jQuery("td", _tr).removeClass("selected");
                        _tr.removeClass("selected");
                        jQuery("input:checkbox", _tr).attr("checked", "");
                    }
                    else {
                        jQuery("td", _tr).addClass("selected");
                        _tr.addClass("selected");
                        jQuery("input:checkbox", _tr).attr("checked", "checked");
                    }
                }

            };

            //A: triggero click per colorare la riga
            jQuery("input:radio:checked", that).trigger("click");
            //B: triggero checked -> se usassi il click la checkbox si deselezionerebbe
            jQuery("input:checkbox:checked", that).trigger("checked");

        });
    }
	$.fn.comodoclick = ComodoClick;

	//AUTOLOAD
	$(document).ready(function(){
		$('table.comodoclick').comodoclick();
	});
})(jQuery);

Popularity: 3% [?]

© 2010 Massimiliano Balestrieri | Thanks, WordPress | Sandbox theme | Standards Compliant XHTML & CSS | RSS Posts & Comments