(function() {

// MAXB.NET LABS

})();

javascript, jquery, plugins

comodoclick

Posted on by Massimiliano Balestrieri | Comments (2)

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);

php

WsCrud – esempio di webservice con nusoap/php

Posted on by Massimiliano Balestrieri | Comments Off

LINK DEMO:

DOWNLOAD

ISTRUZIONI:

  • Estrarre il pacchetto (htdocs del vostro webserver)
  • configurare il file config/config.php
	define('DB_HOST', '');//esempio localhost
	define('DB_USER', '');//esempio wscrud
	define('DB_NAME', '');//esempio wscrud
	define('DB_PWD', '');//esempio wscrud
	define('WSDL', '');//esempio http://maxb.net/scripts/wscrud/?wsdl
  • creare il database e importare il dump presente in config/db.sql

LIBRERIE DA SCARICARE A PARTE:

  1. adodb_lite
  2. simpletest
  3. nusoap

wscrud

Una volta scaricate ed estratte le librerie dovranno essere inserite nella directory libs come nell’immagine.

Non sono un grande esperto di servizi. Mi è capitato di farne e di usufruirne.

Questa volta ho deciso di estrapolare dall’ultimo lavoro una sorta di scheletro.

Il servizio spiegato:

Inclusioni di librerie:

require_once(dirname(__FILE__) . '/libs/adodb_lite/adodb.inc.php');
require_once(dirname(__FILE__) . '/libs/nusoap-0.7.3/lib/nusoap.php');

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

require_once(dirname(__FILE__) . '/includes/exception.php');
require_once(dirname(__FILE__) . '/includes/application.php');
require_once(dirname(__FILE__) . '/includes/conn.php');
require_once(dirname(__FILE__) . '/includes/db.php');

Inizializzazione server (vedere il config per capire le costanti):

$server = new nusoap_server();
$server->configureWSDL(APP_NAME_SPACE,APP_TARGET_NAME_SPACE);
$server->wsdl->schemaTargetNamespace = APP_TARGET_NAME_SPACE;

Tipi complessi registrati:


$server->wsdl->addComplexType(
	'record',
	'complexType',
	'struct',
	'all',
	'',
	array(
		'id' => array('name'=>'id','type'=>'xsd:int'),
		'text' => array('name'=>'text','type'=>'xsd:string'),
	)
);

$server->wsdl->addComplexType(
	'array_of_record',
	'complexType',
	'array',
	'',
	'SOAP-ENC:Array',
	array(),
	array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:record[]')),
	'tns:record'
);

I metodi esposti:


$server->register(
	'put_record',
	array('text'=>'xsd:string'),
	array('id'=>'xsd:int'),
	APP_URN,
       APP_URN . '#put_record',
       'rpc',
       'encoded',
	''
);

function put_record($text){
	try{
		$app = new MyApplication();
		return $app->dao->put_record($text);
	}catch(Exception $e){
		return new soap_fault($e->getCode(), 'server', $e->getMessage());
	}
}

$server->register(
	'search_record',
	array(
		'id'=>'xsd:int',
		'text'=>'xsd:string',
	),
	array('return'=>'tns:array_of_record'),
	APP_URN,
    APP_URN . '#search_record',
    'rpc',
    'encoded',
	''
);

function search_record($id, $text){
	try{
		$app = new MyApplication();
		return $app->dao->search_record($id, $text);
	}catch(Exception $e){
		return new soap_fault($e->getCode(), 'server', $e->getMessage());
	}
}

$server->register(
	'get_record',
	array('id'=>'xsd:int'),
	array('return'=>'tns:record'),
	APP_URN,
    APP_URN . '#get_record',
    'rpc',
    'encoded',
	''
);

function get_record($id){
	try{
		$app = new MyApplication();
		return $app->dao->get_record($id);
	}catch(Exception $e){
		return new soap_fault($e->getCode(), 'server', $e->getMessage());
	}
}

$server->register(
	'delete_record',
	array('id'=>'xsd:int'),
	array('return'=>'xsd:boolean'),
	APP_URN,
    APP_URN . '#delete_record',
    'rpc',
    'encoded',
	''
);

function delete_record($id){
	try{
		$app = new MyApplication();
		return $app->dao->delete_record($id);
	}catch(Exception $e){
		return new soap_fault($e->getCode(), 'server', $e->getMessage());
	}
}

$server->register(
	'update_record',
	array('id'=>'xsd:int', 'text' => 'xsd:string'),
	array('return'=>'xsd:boolean'),
	APP_URN,
    APP_URN . '#update_record',
    'rpc',
    'encoded',
	''
);

function update_record($id, $text){
	try{
		$app = new MyApplication();
		return $app->dao->update_record($id, $text);
	}catch(Exception $e){
		return new soap_fault($e->getCode(), 'server', $e->getMessage());
	}
}

L’output del “server”:

$HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : file_get_contents("php://input");
$server->service($HTTP_RAW_POST_DATA);

Attenzione a quel file_get_contents(“php://input”);
Ho sclerato parecchio per far girare questo servizio sul mio hosting.

IL CLIENT

L’esempio del client VERAMENTE basico senza librerie senza divisioni.
GREZZO. Anche l’html. Giusto il form e il meta per la codifica di invio dei dati.

require_once(dirname(__FILE__) . '/../config/config.php');
error_reporting(E_ALL);
function get_client(){
	require_once(dirname(__FILE__) . '/../libs/nusoap-0.7.3/lib/nusoap.php');
	$url = WSDL;
	$client = new nusoap_client( $url, true );
	return $client;
}

$client = get_client();
$args = array();
$records = $client->call( 'search_record', $args );

if(isset($_POST['save'])){
	$_POST['text'] = stripslashes($_POST['text']);
	$client = get_client();
	if($_POST['id'] == 0){
		$args = array( 'text' => $_POST['text']);
		$result = $client->call( 'put_record', $args );
	}else{
		$args = array( 'id' => $_POST['id'], 'text' => $_POST['text']);
		$result = $client->call( 'update_record', $args );
	}
	header('Location:?do=index');
}
$do = isset($_GET['do']) ? $_GET['do'] : false;
$data = array('id' => 0, 'text' => '');
switch($do){
	case 'edit':
		$client = get_client();
		$args = array( 'id' => $_GET['id']);
		$data = $client->call( 'get_record', $args );
	break;
	case 'delete':
		$client = get_client();
		$args = array(  'id' => $_GET['id']);
		$result = $client->call( 'delete_record', $args );
		header('Location:?do=index');
	break;
}

<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<form method="post" action="#">
<p><textarea name="text" id="text"><?php echo $data['text']?></textarea></p>
<p>
<input type="hidden" name="id" id="id" value="<?php echo $data['id'] ?>" />
<input type="submit" name="save" id="save" value="save" />
</p>
</form>
<table>
<thead>
<tr>
	<th>ID</th>
	<th>TEXT</th>
	<th>ACTIONS</th>
<tr>
</thead>
<?php if(isset($records[0])){ ?>
<tbody>
<?php foreach($records as $k => $v){ ?>
<tr>
	<td><?php echo $v['id']?></td>
	<td><?php echo $v['text']?></td>
	<td>
		<a href="?do=edit&amp;amp;id=<?php echo $v['id']?>">edit</a>
		<a href="?do=delete&amp;amp;id=<?php echo $v['id']?>">del</a>
	</td>
<tr>
<?php } ?>
</tbody>
<?php } ?>
<table>

All’interno della directory client troverete due client nativi (estensione soap del php5) : client2.php e client3.php.
Su questo hosting non girano.
Provateli se volete. client3.php usa il metodo “ufficiale” per chiamare i metodi remoti. NON FUNZIONA!

ubuntu

Jaunty Jackalope & Aptana

Posted on by Massimiliano Balestrieri | Comments (2)

C’è un problema tra Aptana e le ultime 2 versioni di ubuntu: XulRunner.
Ubuntu non ha mantenuto nei repository XulRunner di Firefox 2.

Io ho seguito queste istruzioni.

  • scaricare xulrunner-1.8.1.3
  • estrarre il tar.gz
  • spostare il contenuto estratto in /usr/lib (sudo mv xulrunner-1.8.1.3 /usr/lib/)
  • installare via synaptic/apt java 1.6 (sun)
  • creare un file sh eseguibile nella directory di aptana e usare l’sh per lanciare l’ide
#!/bin/bash
MOZILLA_FIVE_HOME=/usr/lib/xulrunner-1.8.1.3
if [ $LD_LIBRARY_PATH ]; then
LD_LIBRARY_PATH=$MOZILLA_FIVE_HOME:$LD_LIBRARY_PATH
else
LD_LIBRARY_PATH=$MOZILLA_FIVE_HOME
fi
JAVA_HOME=/usr/lib/jvm/java-6-sun
export MOZILLA_FIVE__HOME
export LD_LIBRARY_PATH
export JAVA_HOME
echo $MOZILLA_FIVE_HOME $JAVA_HOME $LD_LIBRARY_PATH
/opt/aptana/AptanaStudio -vm /usr/lib/jvm/java-6-sun/jre/bin/java

ubuntu

Jaunty Jackalope – Nvidia Separate X-screen & Gnome

Posted on by Massimiliano Balestrieri | Comments Off

Ieri ho installato Jaunty, la “lepre cornuta”.

Tutto bene. Ho installato da zero su una partizione vuota. Ho configurato il sistema e installato tutta una serie di applicazioni che mi servono per lavoro (vmware, sqldeveloper, skype, java, eclipse, lampp, filezilla).

Per vmware ho seguito le istruzioni per ubuntu 8.10, soprattutto queste.

Miglioramenti evidenti non ne ho visti. L’icona di “wait” è tornata quella standard. Nella 8.10 ogni volta che il sistema entrava in stato di wait il cursore prendeva la forma di “infinito” scentrata rispetto al cursore col risultato che invece di aprire una certa applicazione ne aprivi un altra (o peggio).

Altra miglioria: il sistema di “focus” con doppio monitor. Prima bastava spostare il mouse su un monitor per spostare il focus. Ora devi cliccare. Per me era un bug non certo una funzionalità.

A parte questo il sistema è identico. Magagne comprese. Presenta lo stesso problema sul doppio monitor. Quando lanci un applicazione dal monitor secondario (driver nvidia, configurazione separate X-screen) l’applicazione parte sul monitor 1.

Ho risolto usando uno script “ponte”.
Ho creato un file eseguibile nella mia home

touch  /home/max/bin/display.sh
chmod +x  /home/max/bin/display.sh

Il ponte fa solamente questo:

#!/bin/bash
DISPLAY=":0.1" $1

A questo punto è stato sufficiente precedere nel launcher il ponte.

Tasto destro -> Proprietà -> Comando

DA
/opt/eclipse-3.3.1.1/eclipse
A
/home/max/bin/display.sh /opt/eclipse-3.3.1.1/eclipse

E così per tutti i launchers del monitor secondario (nautilus, kate, gedit, gnome-terminal).

Per concludere… rimango un nostalgico di kde3.
Maledetta Trolltech!

php, snippets

MyPearLogComposite

Posted on by Massimiliano Balestrieri | Comments Off

Pubblico una classe per effettuare il log composito con PEAR::Log.
In sviluppo il log potrà essere usato in maniera abbondante (entrata/uscita dei metodi ad esempio). Questo causerà frequenti accessi al file di log.
In produzione la maschera impostata nello switch eviterà l’accesso al file per i log di tipo PEAR_LOG_DEBUG (valore di default) ma manterrà i log di tipo ERROR e i log di tipo EMERG.
In più per il log di tipo EMERG verrà inviata una mail. Il metodo _rotate della classe garantirà una rotazione del file al raggiungimento di N bytes (vedi costante LOG_SIZE_ROTATION).

set_include_path(dirname(__FILE__) .'/lib/PEAR-1.7.2/:'.get_include_path());

require_once(dirname(__FILE__) . '/lib/PEAR-1.7.2/PEAR.php');
require_once(dirname(__FILE__) . '/lib/Log-1.11.3/Log.php');
require_once(dirname(__FILE__) . '/lib/Mail-1.2.0b1/Mail.php');

$env = 1;
switch($env){
	case 0://development
		define('MASK_ERROR', PEAR_LOG_DEBUG);
	break;
	case 1://production
		define('MASK_ERROR', PEAR_LOG_ERR);
	break;
}
define('APPLICATION_NAME', 'mylog');
define('MAIL_MASK_ERROR', PEAR_LOG_EMERG);
define('MAIL_WEBMASTER', 'MAILTO');
define('MAIL_FROM', 'MAILFROM');
define('LOG_FILE', dirname(__FILE__) . '/logs/'.APPLICATION_NAME.'.txt');
define('LOG_SIZE_ROTATION',1000000);

class MyPearLogComposite{

	public $logger;

	public function __construct(){
		$this->_check_rotate();
		$conf = array('mode' => 0600, 'timeFormat' => '%X %x');
		$file = &Log::singleton('file', LOG_FILE, APPLICATION_NAME , $conf);
		$mask = Log::MAX(MASK_ERROR);
		$file->setMask($mask);
		$conf = array('from' => MAIL_FROM,'subject' => APPLICATION_NAME . ' Important log events');
		$mail = &Log::singleton('mail', MAIL_WEBMASTER, APPLICATION_NAME, $conf);
		$mask = Log::MAX(MAIL_MASK_ERROR);
		$mail->setMask($mask);
		$this->logger = &Log::singleton('composite');
		$this->logger->addChild($file);
		$this->logger->addChild($mail);
	}
	private function _check_rotate(){
		$size = @filesize(LOG_FILE);
		if($size > LOG_SIZE_ROTATION)
        	$this->_rotate();

	}
	private function _rotate(){
		$file = LOG_FILE . '.' . date('Y-m-d');
        rename(LOG_FILE, $file);
	}
}

$log = new MyPearLogComposite();

$log->logger->log('log something');
$log->logger->log('log log');
$log->logger->log('log error', PEAR_LOG_ERR);
$log->logger->log('emergency', PEAR_LOG_EMERG);

//in development
//log file:
/*
12:32:30 24/04/2009 mylog [info] log something
12:32:30 24/04/2009 mylog [info] log log
12:32:30 24/04/2009 mylog [error] log error
12:32:30 24/04/2009 mylog [emergency] emergency
*/
//mail:
/*
To: MAILTO
Subject: mylog Important log events
From: MAILFROM
User-Agent: PEAR Log Package
Apr 24 12:40:25 mylog [emergency] emergency
*/

//in production
//log file:
/*
12:42:25 04/24/09 mylog [error] log error
12:42:25 04/24/09 mylog [emergency] emergency
*/
//mail:
/*
To: MAILTO
Subject: mylog Important log events
From: MAILFROM
User-Agent: PEAR Log Package
Apr 24 12:42:25 mylog [emergency] emergency
*/