<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog Shivato Web</title>
	<atom:link href="http://www.shivato-web.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.shivato-web.com/blog</link>
	<description>Developpement web</description>
	<lastBuildDate>Sun, 28 Aug 2011 18:13:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>[TUTO] Classe de parsing Google Agenda en PHP</title>
		<link>http://www.shivato-web.com/blog/php/tuto-classe-de-parsing-google-agenda-en-php/</link>
		<comments>http://www.shivato-web.com/blog/php/tuto-classe-de-parsing-google-agenda-en-php/#comments</comments>
		<pubDate>Sun, 28 Aug 2011 17:46:15 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Google Agenda]]></category>
		<category><![CDATA[Tutoriel]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=117</guid>
		<description><![CDATA[On voit partout sur le net que l'on peut lire les données de Google Agenda avec Zend Framework, mais si on veut seulement lire les données on peut simplement utiliser PHP. Tout d'abord, il faut récupérer l'adresse du flux xml de l'agenda que l'on veut parser. Ouvrez les options de l'agenda désiré et cliquez sur [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/google-agenda.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/google-agenda.png" alt="" title="google-agenda" width="180" height="130" class="aligncenter size-full wp-image-112" /></a></p>
<p>On voit partout sur le net que l'on peut lire les données de Google Agenda avec Zend Framework, mais si on veut seulement lire les données on peut simplement utiliser PHP.</p>
<p>Tout d'abord, il faut récupérer l'adresse du flux xml de l'agenda que l'on veut parser.<br />
Ouvrez les options de l'agenda désiré et cliquez sur "Paramètres de l'agenda".</p>
<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/parametre-agenda.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/parametre-agenda.png" alt="" title="parametre-agenda" width="432" height="320" class="alignleft size-full wp-image-114" style="float:none;border:1px solid black;" /></a></p>
<p>Cliquez sur l'icône xml de l'adresse url public ou privée, ça fonctionne avec les 2.</p>
<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/lien-url1.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/lien-url.png" alt="" title="lien-url" width="648" height="214" class="alignleft size-full wp-image-113" style="float:none;border:1px solid black;" /></a></p>
<p>Copiez l'adresse complète affiché.</p>
<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/url-agenda1.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/url-agenda1.png" alt="" title="url-agenda" width="450" height="93" class="alignleft size-full wp-image-128" style="float:none;border:1px solid black;" /></a></p>
<p>Maintenant nous allons créer 3 classes (GoogleAgenda, GoogleAgendaEvent et GoogleAgendaException).</p>
<p>Commençons par la plus simple, la classe d'exception que nous mettrons dans le fichier GoogleAgendaException.php :</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * Classe d'exception pour GoogleAgenda
 * @author shivato
 * @version 1.0
 *
 */
class GoogleAgendaException extends Exception {

}
</pre>
<p>Maintenant nous allons créer notre classe d'entité d’évènements que nous mettrons dans le fichier GoogleAgendaEvent.php.<br />
Cette classe contient toutes les valeurs d'un évènement, elle ne contient que des variables protected avec leurs getteurs et setteurs :</p>
<p><span id="more-117"></span></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * Classe d'entité d'évènement Google Agenda
 * @author Shivato Web
 * @version 1.0
 *
 */
class GoogleAgendaEvent {

	protected $_sTitle;
	protected $_dStartDate;
	protected $_dEndDate;
	protected $_sAddress;
	protected $_sDescription;
	protected $_sAuthorName;
	protected $_sAuthorEmail;
	protected $_dPublishedDate;
	protected $_dUpdatedDate;
	protected $_sUrlDetail;
	protected $_aPersons = array();
	protected $_aReminders = array();
	protected $_dOriginalDate;
	protected $_bRecurs = false;

	/**
	 * Constructeur
	 * @return void
	 */
	public function __construct() { }

	/**
	 * setteur titre
	 * @param string $sTitle
	 * @return void
	 */
	public function setTitle($sTitle) {
		$this-&gt;_sTitle = $sTitle;
	}

	/**
	 * getteur titre
	 * @return string
	 */
	public function getTitle() {
		return $this-&gt;_sTitle;
	}

	/**
	 * setteur date de début
	 * @param date $dStartDate
	 * @return void
	 */
	public function setStartDate($dStartDate) {
		$this-&gt;_dStartDate = $dStartDate;
	}

	/**
	 * getteur date de début
	 * @return date
	 */
	public function getStartDate() {
		return $this-&gt;_dStartDate;
	}

	/**
	 * setteur date de fin
	 * @param date $dEndDate
	 * @return void
	 */
	public function setEndDate($dEndDate) {
		$this-&gt;_dEndDate = $dEndDate;
	}

	/**
	 * getteur date de fin
	 * @return date
	 */
	public function getEndDate() {
		return $this-&gt;_dEndDate;
	}

	/**
	 * setteur adresse
	 * @param string $sAddress
	 * @return void
	 */
	public function setAddress($sAddress) {
		$this-&gt;_sAddress = $sAddress;
	}

	/**
	 * getteur adresse
	 * @return string
	 */
	public function getAddress() {
		return $this-&gt;_sAddress;
	}

	/**
	 * setteur description
	 * @param string $sDescription
	 * @return void
	 */
	public function setDescription($sDescription) {
		$this-&gt;_sDescription = $sDescription;
	}

	/**
	 * getteur description
	 * @return string
	 */
	public function getDescription() {
		return $this-&gt;_sDescription;
	}

	/**
	 * setteur date de publication
	 * @param date $dPublishedDate
	 * @return void
	 */
	public function setPublishedDate($dPublishedDate) {
		$this-&gt;_dPublishedDate = $dPublishedDate;
	}

	/**
	 * getteur date de publication
	 * @return date
	 */
	public function getPublishedDate() {
		return $this-&gt;_dPublishedDate;
	}

	/**
	 * setteur date de modification
	 * @param date $dModifiedDate
	 * @return void
	 */
	public function setUpdatedDate($dUpdatedDate) {
		$this-&gt;_dUpdatedDate = $dUpdatedDate;
	}

	/**
	 * getteur date de modification
	 * @return date
	 */
	public function getUpdatedDate() {
		return $this-&gt;_dUpdatedDate;
	}

	/**
	 * setteur url détail
	 * @param string $sUrlDetail
	 * @return void
	 */
	public function setUrlDetail($sUrlDetail) {
		$this-&gt;_sUrlDetail = $sUrlDetail;
	}

	/**
	 * getteur url détail
	 * @return string
	 */
	public function getUrlDetail() {
		return $this-&gt;_sUrlDetail;
	}

	/**
	 * setteur du nom de l'auteur de l'évènement
	 * @param string $sAuthorName
	 * @return void
	 */
	public function setAuthorName($sAuthorName) {
		$this-&gt;_sAuthorName = $sAuthorName;
	}

	/**
	 * getteur du nom de l'auteur de l'évènement
	 * @return string
	 */
	public function getAuthorName() {
		return $this-&gt;_sAuthorName;
	}

	/**
	 * setteur du mail de l'auteur de l'évènement
	 * @param string $sAuthorEmail
	 * @return void
	 */
	public function setAuthorEmail($sAuthorEmail) {
		$this-&gt;_sAuthorEmail = $sAuthorEmail;
	}

	/**
	 * getteur du mail de l'auteur de l'évènement
	 * @return string
	 */
	public function getAuthorEmail() {
		return $this-&gt;_sAuthorEmail;
	}

	/**
	 * setteur des personnes attaché à l'évènement
	 * @param array $aPersons
	 * @return void
	 */
	public function setPersons(array $aPersons) {
		$this-&gt;_aPersons = $aPersons;
	}

	/**
	 * getteur des personnes attaché à l'évènement
	 * retourne un tableau d'objet de type stdClass() : $aPersons[0]-&gt;name, $aPersons[0]-&gt;email, $aPersons[0]-&gt;role, $aPersons[0]-&gt;status
	 * @return array
	 */
	public function getPersons() {
		return $this-&gt;_aPersons;
	}

	/**
	 * setteur des rappels attaché à l'évènement
	 * @param array $aReminders
	 * @return void
	 */
	public function setReminders(array $aReminders) {
		$this-&gt;_aReminders = $aReminders;
	}

	/**
	 * getteur des rappels attaché à l'évènement
	 * retourne un tableau d'objet de type stdClass() : $aReminders[0]-&gt;type, $aReminders[0]-&gt;minutes
	 * @return array
	 */
	public function getReminders() {
		return $this-&gt;_aReminders;
	}

	/**
	 * setteur date d'origine
	 * @param date $dDate
	 * @return void
	 */
	public function setOriginalDate($dOriginalDate) {
		$this-&gt;_dOriginalDate = $dOriginalDate;
	}

	/**
	 * getteur date d'origine
	 * @return date
	 */
	public function getOriginalDate() {
		return $this-&gt;_dOriginalDate;
	}

	/**
	 * setteur évènement récurrent
	 * @param bool $bRecurs
	 * @return void
	 */
	public function setRecurs($bRecurs) {
		$this-&gt;_bRecurs = $bRecurs;
	}

	/**
	 * getteur évènement récurrent
	 * @return bool
	 */
	public function getRecurs() {
		return $this-&gt;_bRecurs;
	}
}
</pre>
<p>Cette classe n'a pas vraiment besoin d'explication, les commentaires sont assez parlant.</p>
<p>Il nous reste notre dernière classe à créer qui va faire le traitement, nous la mettrons dans le fichier GoogleAgenda.php :</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
/**
 * Classe de lecture d'un agenda Google
 * @author Shivato Web
 * @version 1.0
 * @link http://www.shivato-web.com/blog/php/tuto-classe-de-parsing-google-agenda-en-php
 * @example :
 * $oAgenda = new GoogleAgenda($sFeed);
 * $aEvents = $oAgenda-&gt;getEvents($aOptions);
 * $oAgenda-&gt;getTitle();
 * foreach ($aEvents as $oEvent) {
 * 		$oEvent-&gt;getTitle();
 * 		$oEvent-&gt;getStartDate();
 * 		$oEvent-&gt;getEndDate();
 * 		$oEvent-&gt;getAddress();
 * 		$oEvent-&gt;getDescription();
 * }
 * $aEventsNext = $oAgenda-&gt;getNextEvents();
 * $aEventsPrevious = $oAgenda-&gt;getPreviousEvents(); $aEventsPrevious == $aEvents
 *
 * Les urls sont accessibles si on est logué sur le bon compte de l'agenda ou si l'agenda a été rendu public
 */
class GoogleAgenda {
	//variables interne de la classe
	protected $_sFeed;
	protected $_dStartMin;
	protected $_dStartMax;
	protected $_sSortorder;
	protected $_sOrderby;
	protected $_iMaxResults;
	protected $_iStartIndex;
	protected $_sUrlNext;
	protected $_sUrlPrevious;
	protected $_aEvents;
	protected $_sSearch;
	protected $_bSingleEvents;
	protected $_bFutureEvents;
	protected $_sTimezone;
	protected $_bShowDeleted;
	//variables disponible
	protected $_dUpdatedDate;
	protected $_sTitle;
	protected $_sSubtitle;
	protected $_sUrlPublic;
	protected $_sAuthorName;
	protected $_sAuthorEmail;

	const MAX_RESULTS_DEFAULT = 5;

	/**
	 * Définie l'agenda avec lequel on travail
	 * @param string $sFeed url de l'agenda
	 * @param bool $bFull permet d'avoir toutes les variables rempli séparément, sinon met adresse, date... dans description (default true)
	 * @return void
	 * @throws GoogleAgendaException si l'url n'est pas valide
	 */
	public function __construct($sFeed, $bFull = true) {
		if ($bFull) {
			$sFeed = mb_strrchr($sFeed, 'basic', true) . 'full';
		}

		$sFeedContent = @file_get_contents($sFeed);
		if ($sFeedContent !== false &amp;&amp; !empty($sFeedContent)) {
			$this-&gt;_sFeed = $sFeed;
		}
		else {
			throw new GoogleAgendaException('L\'url ['.$sFeed.'] n\'est pas valide.');
		}
	}

	/**
	 * getteur de la date de maj de l'agenda
	 * @return date
	 */
	public function getUpdatedDate() {
		return $this-&gt;_dUpdatedDate;
	}

	/**
	 * getteur du titre de l'agenda
	 * @return string
	 */
	public function getTitle() {
		return $this-&gt;_sTitle;
	}

	/**
	 * getteur du sous titre de l'agenda
	 * @return string
	 */
	public function getSubtitle() {
		return $this-&gt;_sSubtitle;
	}

	/**
	 * getteur de l'url public de l'agenda
	 * @return string
	 */
	public function getUrlPublic() {
		return $this-&gt;_sUrlPublic;
	}

	/**
	 * getteur du nom de l'auteur de l'agenda
	 * @return string
	 */
	public function getAuthorName() {
		return $this-&gt;_sAuthorName;
	}

	/**
	 * getteur de l'adresse email de l'auteur de l'agenda
	 * @return string
	 */
	public function getAuthorEmail() {
		return $this-&gt;_sAuthorEmail;
	}

	/**
	 * Getteur des évènements selon les paramètres
	 * Options :
	 * (date Y-m-d) startmin : date du début de la lecture (default : date du jour)
	 * (date Y-m-d) startmax : date de la fin de la lecture (ne prend pas les évènement de la date) (default : null)
	 * (string) sortorder : tri des évènements, options disponible : ascending, descending (default : ascending)
	 * (string) orderby : ordre des évènements, options disponible : starttime, lastmodified (default : starttime)
	 * (int) maxresults : nombre d'évènements retournés (default : self::MAX_RESULTS_DEFAULT)
	 * (int) startindex : page de résultat de la lecture (default : 1)
	 * (string) search : texte recherché dans les évènements (default : null)
	 * (string) singleevents : prend les évènements récurrents à leur date, sinon toutes les dates suivantes sont dans le premier évènement récurrent trouvé
	 * 				 (déconseillé, ne marche pas vraiment bien), options : 'true', 'false' (default : 'true')
	 * (string) futureevents : ne prend que les évènements à venir ou prend aussi ceux déjà passé de la première journée, options : 'true', 'false' (default : 'false')
	 * (string) timezone : défini le fuseau horaire (default : Europe/Paris)
	 * (string) showdeleted : prend en compte les évènements supprimés, options : 'true', 'false' (default : 'false')
	 * @param array $aOptions (options : startmin, startmax, sortorder, orderby, maxresults, startindex, search, singleevents, futureevents, timezone, showdeleted)
	 * @return array tableau d'objets des évènements de l'agenda
	 * @link options : http://code.google.com/intl/fr/apis/calendar/data/2.0/reference.html#Parameters
	 * @link options : http://code.google.com/intl/fr/apis/gdata/docs/2.0/reference.html#Queries
	 */
	public function getEvents(array $aOptions = array()) {
		//récupération des options
		$this-&gt;_dStartMin = isset($aOptions['startmin']) ? $aOptions['startmin'] : date('Y-m-d');
		$this-&gt;_dStartMax = isset($aOptions['startmax']) ? $aOptions['startmax'] : '';
		$this-&gt;_sSortorder = isset($aOptions['sortorder']) ? $aOptions['sortorder'] : 'ascending';
		$this-&gt;_sOrderby = isset($aOptions['orderby']) ? $aOptions['orderby'] : 'starttime';
		$this-&gt;_iMaxResults = isset($aOptions['maxresults']) ? $aOptions['maxresults'] : self::MAX_RESULTS_DEFAULT;
		$this-&gt;_iStartIndex = isset($aOptions['startindex']) ? $aOptions['startindex'] : 1;
		$this-&gt;_sSearch = isset($aOptions['search']) ? $aOptions['search'] : '';
		$this-&gt;_bSingleEvents = isset($aOptions['singleevents']) ? $aOptions['singleevents'] : 'true';
		$this-&gt;_bFutureEvents = isset($aOptions['futureevents']) ? $aOptions['futureevents'] : 'false';
		$this-&gt;_sTimezone = isset($aOptions['timezone']) ? $aOptions['timezone'] : 'Europe/Paris';
		$this-&gt;_bShowDeleted = isset($aOptions['showdeleted']) ? $aOptions['showdeleted'] : 'false';

		//construction de l'url avec les options reçus
		$sUrl = $this-&gt;_sFeed . '?' .
		( !empty($this-&gt;_dStartMin) ? 'start-min=' . $this-&gt;_dStartMin . '&amp;' : '' ) .
		( !empty($this-&gt;_dStartMax) ? 'start-max=' . $this-&gt;_dStartMax . '&amp;' : '' ) .
		( !empty($this-&gt;_sSortorder) ? 'sortorder=' . $this-&gt;_sSortorder . '&amp;' : '' ) .
		( !empty($this-&gt;_sOrderby) ? 'orderby=' . $this-&gt;_sOrderby . '&amp;' : '' ) .
		( !empty($this-&gt;_iMaxResults) ? 'max-results=' . $this-&gt;_iMaxResults . '&amp;' : '' ) .
		( !empty($this-&gt;_iStartIndex) ? 'start-index=' . $this-&gt;_iStartIndex . '&amp;' : '' ) .
		( !empty($this-&gt;_sSearch) ? 'q=' . $this-&gt;_sSearch . '&amp;' : '' ) .
		( !empty($this-&gt;_bSingleEvents) ? 'singleevents=' . $this-&gt;_bSingleEvents . '&amp;' : '' ) .
		( !empty($this-&gt;_bFutureEvents) ? 'futureevents=' . $this-&gt;_bFutureEvents . '&amp;' : '' ) .
		( !empty($this-&gt;_sTimezone) ? 'ctz=' . $this-&gt;_sTimezone . '&amp;' : '' ) .
		( !empty($this-&gt;_bShowDeleted) ? 'showdeleted=' . $this-&gt;_bShowDeleted . '&amp;' : '' );

		$this-&gt;loadUrl($sUrl);

		return $this-&gt;_aEvents;
	}

	/**
	 * Getteur des évènements suivants avec les mêmes paramètres
	 * @return array tableau d'objets des évènements de l'agenda, un tableau vide si l'url n'existe pas
	 */
	public function getNextEvents() {
		if (!empty($this-&gt;_sUrlNext)) {
			$this-&gt;loadUrl($this-&gt;_sUrlNext);
			return $this-&gt;_aEvents;
		}
		else {
			return array();
		}
	}

	/**
	 * Getteur des évènements précédents avec les mêmes paramètres
	 * Utilisable si la fonction getNextEvents() a été utilisés ou si l'option start-index &gt; 1 a été utilisé
	 * @return array tableau d'objets des évènements de l'agenda, un tableau vide si l'url n'existe pas
	 */
	public function getPreviousEvents() {
		if (!empty($this-&gt;_sUrlPrevious)) {
			$this-&gt;loadUrl($this-&gt;_sUrlPrevious);
			return $this-&gt;_aEvents;
		}
		else {
			return array();
		}
	}

	/**
	 * Charge l'url du flux xml de l'agenda et rempli les valeurs de l'instance correspondant à l'agenda
	 * @param string $sUrl
	 * @return void
	 */
	protected function loadUrl($sUrl) {
		$this-&gt;_aEvents = array();

		//lecture du fichier XML
		$oXml = simplexml_load_file($sUrl);
		if ($oXml !== false) {
			$this-&gt;_dUpdatedDate = isset($oXml-&gt;updated) ? date('Y-m-d H:i:s', strtotime($oXml-&gt;updated)) : '';
			$this-&gt;_sTitle = isset($oXml-&gt;title) ? (string) $oXml-&gt;title : '';
			$this-&gt;_sSubtitle = isset($oXml-&gt;subtitle) ? (string) $oXml-&gt;subtitle : '';
			$this-&gt;_sAuthorName = isset($oXml-&gt;author) &amp;&amp; isset($oXml-&gt;author-&gt;name) ? (string)$oXml-&gt;author-&gt;name : '';
			$this-&gt;_sAuthorEmail = isset($oXml-&gt;author) &amp;&amp; isset($oXml-&gt;author-&gt;email) ? (string)$oXml-&gt;author-&gt;email : '';
			$this-&gt;_sUrlPublic = '';
			$this-&gt;_sUrlNext = '';
			$this-&gt;_sUrlPrevious = '';
			if (isset($oXml-&gt;link)) {
				foreach ($oXml-&gt;link as $oLink) {
					if ($oLink-&gt;attributes()-&gt;rel == 'alternate') {
						$this-&gt;_sUrlPublic = (string) $oLink-&gt;attributes()-&gt;href;
					}
					else if ($oLink-&gt;attributes()-&gt;rel == 'next') {
						$this-&gt;_sUrlNext = (string) $oLink-&gt;attributes()-&gt;href;
					}
					else if ($oLink-&gt;attributes()-&gt;rel == 'previous') {
						$this-&gt;_sUrlPrevious = (string) $oLink-&gt;attributes()-&gt;href;
					}
				}
			}

			if (isset($oXml-&gt;entry)) {
				foreach ($oXml-&gt;entry as $oDataEvent) {
					$this-&gt;setEvent($oDataEvent);
				}
			}
		}

	}

	/**
	 * Crée un nouvel objet GoogleAgendaEvent et l'affecte au tableau d'évènements
	 * @param SimpleXMLElement $oData
	 * @return void
	 */
	protected function setEvent(SimpleXMLElement $oData) {
		$oEvent = new GoogleAgendaEvent();
		$oDataChild = $oData-&gt;children('http://schemas.google.com/g/2005');

		$oEvent-&gt;setTitle(isset($oData-&gt;title) ? (string) $oData-&gt;title : '');
		$oEvent-&gt;setPublishedDate(isset($oData-&gt;published) ? date('Y-m-d H:i:s', strtotime($oData-&gt;published)) : '');
		$oEvent-&gt;setUpdatedDate(isset($oData-&gt;updated) ? date('Y-m-d H:i:s', strtotime($oData-&gt;updated)) : '');
		$oEvent-&gt;setAuthorName(isset($oData-&gt;author) &amp;&amp; isset($oData-&gt;author-&gt;name) ? (string) $oData-&gt;author-&gt;name : '');
		$oEvent-&gt;setAuthorEmail(isset($oData-&gt;author) &amp;&amp; isset($oData-&gt;author-&gt;email) ? (string) $oData-&gt;author-&gt;email : '');
		$oEvent-&gt;setDescription(isset($oData-&gt;content) ? (string) $oData-&gt;content : '');
		$oEvent-&gt;setAddress(isset($oDataChild-&gt;where) ? (string) $oDataChild-&gt;where-&gt;attributes()-&gt;valueString : '');

		if (isset($oData-&gt;link)) {
			foreach ($oData-&gt;link as $oLink) {
				if ($oLink-&gt;attributes()-&gt;rel == 'alternate') {
					$oEvent-&gt;setUrlDetail((string) $oLink-&gt;attributes()-&gt;href);
					break;
				}
			}
		}

		if (isset($oDataChild-&gt;who)) {
			$aPersons = array();
			foreach ($oDataChild-&gt;who as $oWho) {
				$aPersons[] = $this-&gt;parsePerson($oWho);
			}
			$oEvent-&gt;setPersons($aPersons);
		}

		if (isset($oDataChild-&gt;originalEvent)) {
			$oEvent-&gt;setOriginalDate((string) $oDataChild-&gt;originalEvent-&gt;when-&gt;attributes()-&gt;startTime);
		}

		if (isset($oDataChild-&gt;when)) {
			$oEvent-&gt;setStartDate(date('Y-m-d H:i:s', strtotime($oDataChild-&gt;when-&gt;attributes()-&gt;startTime)));
			$oEvent-&gt;setEndDate(date('Y-m-d H:i:s', strtotime($oDataChild-&gt;when-&gt;attributes()-&gt;endTime)));

			if (isset($oDataChild-&gt;when-&gt;reminder)) {
				$aReminders = array();
				foreach ($oDataChild-&gt;when-&gt;reminder as $oReminder) {
					$oReminderEvent = new stdClass();
					$oReminderEvent-&gt;type = (string) $oReminder-&gt;attributes()-&gt;method;
					$oReminderEvent-&gt;minutes = (string) $oReminder-&gt;attributes()-&gt;minutes;
					$aReminders[] = $oReminderEvent;
				}
				$oEvent-&gt;setReminders($aReminders);
			}
		}

		if (isset($oDataChild-&gt;recurrence)) {
			$oEvent-&gt;setRecurs(true);
		}

		$this-&gt;_aEvents[] = $oEvent;
	}

	/**
	 * Parse les informations des personnes participantes
	 * @param SimpleXMLElement $oPerson
	 * @return stdClass
	 */
	protected function parsePerson(SimpleXMLElement $oPerson) {
		if ($oPerson-&gt;attributes()-&gt;rel == 'http://schemas.google.com/g/2005#event.organizer') {
			$sRole = 'Organisateur';
		}
		else {
			$sRole = 'Invité';
		}

		if (isset($oPerson-&gt;attendeeStatus)) {
			switch ($oPerson-&gt;attendeeStatus-&gt;attributes()-&gt;value) {
				case 'http://schemas.google.com/g/2005#event.accepted' :
					$sStatus = 'Présent';
					break;
				case 'http://schemas.google.com/g/2005#event.invited' :
					$sStatus = 'Invité';
					break;
				case 'http://schemas.google.com/g/2005#event.declined' :
					$sStatus = 'Absent';
					break;
				case 'http://schemas.google.com/g/2005#event.tentative' :
					$sStatus = 'Peut-être';
					break;
				default :
					$sStatus = 'Présent';

			}
		}
		else {
			$sStatus = 'Présent';
		}

		$oPersonEvent = new stdClass();
		$oPersonEvent-&gt;name = (string) $oPerson-&gt;attributes()-&gt;valueString;
		$oPersonEvent-&gt;email = (string) $oPerson-&gt;attributes()-&gt;email;
		$oPersonEvent-&gt;role = $sRole;
		$oPersonEvent-&gt;status = $sStatus;
		return $oPersonEvent;

	}
}
</pre>
<p>Que fait on dans cette classe et comment l'utiliser :<br />
Toutes les variables en dessous du commentaire "variables disponibles" possèdes des getteurs, ce sont les données propres à l'agenda, comme son titre, sa date de mise à jour, son url public...<br />
On passe l'url du flux xml que l'on a copié au constructeur, il est possible de mettre le deuxième champ optionnel à false, ce qui ne remplira pas toutes les variables d'évènement (voir commentaire du constructeur). L'appel au constructeur déclenche une exception de type GoogleAgendaException si l'url du flux est invalide.</p>
<p>Pour récupérer un tableau d'objet d'évènements, on appel la méthode getEvents() à laquelle nous pouvons passer un tableau d'options en paramètre (voir commentaire de la méthode pour plus d'informations sur chaque option). Ces options permettent de définir quels évènements de l'agenda nous souhaitons récupérer.<br />
Une fois les options ajoutées à l'url, nous parsons celle-ci avec la méthode loadUrl() qui va lire le flux xml et affecter les données reçues aux variables de l'agenda et des évènements.</p>
<p>Une fois la méthode getEvents() appelée nous pouvons appeler la méthode getNextEvents() qui retournera la suite des évènements avec les mêmes options que getEvents(). Si getNextEvents() est appelée et qu'il n'y a pas de suite, elle retourne un tableau vide, idem pour getPreviousEvents() (celle-ci ne peut pas être appelée après getEvents() sauf si vous avez passé une valeur différente de 1 à startindex en option)</p>
<p>Exemple d'utilisation :
</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
require_once 'GoogleAgenda.php';
require_once 'GoogleAgendaEvent.php';
require_once 'GoogleAgendaException.php';

try {
	$oAgenda = new GoogleAgenda(&quot;https://www.google.com/calendar/feeds/{partie privée de l'url copié}/basic&quot;);
	// Le tableau d'options suivant contient les valeurs par défaut
	$aEvents = $oAgenda-&gt;getEvents(array(
		'startmin' =&gt; date('Y-m-d'),
		'startmax' =&gt; '',
		'sortorder' =&gt; 'ascending',
		'orderby' =&gt; 'starttime',
		'maxresults' =&gt; '5',
		'startindex' =&gt; '1',
		'search' =&gt; '',
		'singleevents' =&gt; 'true',
		'futureevents' =&gt; 'false',
		'timezone' =&gt; 'Europe/Paris',
		'showdeleted' =&gt; 'false'
	));

	echo $oAgenda-&gt;getTitle(); //affiche le titre de l'agenda
	echo $oAgenda-&gt;getAuthorName(); //affiche le nom de l'auteur de l'agenda
	echo $oAgenda-&gt;getUrlPublic(); //affiche l'url public de l'agenda

	foreach ($aEvents as $oEvent) {
		echo $oEvent-&gt;getTitle(); //affiche le titre de l'évènement
		echo $oEvent-&gt;getStartDate(); //affiche la date de début de l'évènement
		echo $oEvent-&gt;getEndDate(); //affiche la date de fin de l'évènement
		foreach ($oEvent-&gt;getPersons() as $oPerson) {
			echo $oPerson-&gt;name; //affiche le nom de la personne convié à l'évènement
			echo $oPerson-&gt;role; //indique si la personne est organisateur ou invité
			echo $oPerson-&gt;status; //indique si la personne est présente, absente, invité (pas répondu) ou sera peut être présente
		}
	}

	$aEventsNext = $oAgenda-&gt;getNextEvents();
}
catch (GoogleAgendaException $e) {
	echo $e-&gt;getMessage();
}
</pre>
<p>Note : les urls de l'agenda et de détails des évènements fonctionnent si vous êtes titulaire du compte et logué ou si l'agenda a été rendu public dans les réglages de Google.</p>
<p>Pour rendre l'agenda public, ouvrez les options de l'agenda et cliquez sur "Partager l'agenda".
</p>
<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/partager-agenda.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/partager-agenda.png" alt="" title="partager-agenda" width="362" height="250" class="alignleft size-full wp-image-115" style="float:none;border:1px solid black;" /></a></p>
<p>Cochez "Rendre cet agenda public" et enregistrez.</p>
<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/agenda-public.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/08/agenda-public.png" alt="" title="agenda-public" width="472" height="137" class="alignleft size-full wp-image-111" style="float:none;border:1px solid black;" /></a></p>
<p>Voilà vous avez maintenant une classe pour parser les agendas Google.<br />
Si vous souhaitez mettre à jour ou supprimé des évènements, il vous faudra passer par Zend Framework.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/php/tuto-classe-de-parsing-google-agenda-en-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Astuce] Réduire la taille des widgets jQuery UI</title>
		<link>http://www.shivato-web.com/blog/javascript/astuce-reduire-la-taille-des-widgets-jquery-ui/</link>
		<comments>http://www.shivato-web.com/blog/javascript/astuce-reduire-la-taille-des-widgets-jquery-ui/#comments</comments>
		<pubDate>Fri, 01 Apr 2011 18:51:41 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[JAVASCRIPT]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jQuery UI]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=100</guid>
		<description><![CDATA[Vous n'avez jamais remarqué que sur le site de démo de jQuery UI les widgets sont toujours plus petits que quand on les insère dans nos pages. A l'époque où je recherchais pour réduire leur taille, dans le code source de la page de démo on pouvait voir qu'il y avait un font-size:80% sur le [...]]]></description>
			<content:encoded><![CDATA[<div style="text-align:center;"><a href="http://www.shivato-web.com/blog/wp-content/uploads/2011/04/JQuery_UI_Logo.png"><img src="http://www.shivato-web.com/blog/wp-content/uploads/2011/04/JQuery_UI_Logo.png" alt="jQuery UI" title="jQuery UI" width="258" height="93" class="aligncenter size-full wp-image-106" /></a></div>
<p>Vous n'avez jamais remarqué que sur le site de démo de <a href="http://jqueryui.com/">jQuery UI</a> les widgets sont toujours plus petits que quand on les insère dans nos pages.</p>
<p>A l'époque où je recherchais pour réduire leur taille, dans le code source de la page de démo on pouvait voir qu'il y avait un font-size:80% sur le body.<br />
Pas très pratique si on veut que 80% sur le widget.<br />
Pour cela, une simple ligne suffit :</p>
<pre class="brush: jscript; light: true; title: ; notranslate">$('#search').autocomplete('widget').css({ fontSize:'80%' });</pre>
<p>Cela fonctionne sur :</p>
<ul>
<li>datepicker</li>
<li>autocomplete</li>
<li>accordion (pour celui là, à 80% on peut obtenir des scrolls sur certains navigateurs, le mieux est de le définir à 90%)</li>
</ul>
<p>Je n'ai pas testé sur les autres widgets, mais ça devrait fonctionner également.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/javascript/astuce-reduire-la-taille-des-widgets-jquery-ui/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Une raison simple de crypter ses mots de passe en MD5</title>
		<link>http://www.shivato-web.com/blog/php/une-raison-simple-de-crypter-ses-mots-de-passe-en-md5/</link>
		<comments>http://www.shivato-web.com/blog/php/une-raison-simple-de-crypter-ses-mots-de-passe-en-md5/#comments</comments>
		<pubDate>Thu, 14 Oct 2010 19:11:16 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Cryptage]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=73</guid>
		<description><![CDATA[Si vous ne cryptez pas vos mots de passe, que vous enregistrez en base un mot de passe comme « AzErTy » et que vous ne prenez pas soin de contrôler la casse au moment de la vérification du login et du password, en tapant « azerty » ou « aZeRtY » ou le bon [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2010/10/cryptage1.jpg"><img class="aligncenter size-full wp-image-75" title="cryptage" src="http://www.shivato-web.com/blog/wp-content/uploads/2010/10/cryptage1.jpg" alt="" width="300" height="225" /></a></p>
<p>Si vous ne cryptez pas vos mots de passe, que vous enregistrez en base un mot de passe comme « AzErTy » et que vous ne prenez pas soin de contrôler la casse au moment de la vérification du login et du password, en tapant « azerty » ou « aZeRtY » ou le bon « AzErTy » vous serez dans tous les cas logués. Normal car MySQL ne gère pas la casse nativement.</p>
<p>Dans le cas où vous ne souhaitez vraiment pas le crypter (pour le renvoyer par email…), vous pouvez vérifier sa casse directement dans votre SELECT :</p>
<pre class="brush: sql; light: true; title: ; notranslate">
SELECT * FROM user WHERE login='monLogin' AND password=BINARY('monPassword');
</pre>
<p>
Ou bien encore pour ne pas y penser à chaque requête, dans votre table mettez l’attribut à BINARY dans le champ correspondant à votre mot de passe.<br />
Utilisez BINARY également sur le login (ou n’importe quel champ) si vous souhaitez gérer la casse dessus.</p>
<p>Mais comme tout le monde le sait, il est préférable de crypter ses mots de passe.<br />
L’avantage du cryptage MD5 est qu’il vous retourne une chaîne de 32 caractères contenant des minuscules et des chiffres. Du coup plus besoin de s’inquiéter de MySQL qui ne gère pas la casse.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/php/une-raison-simple-de-crypter-ses-mots-de-passe-en-md5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[TUTO] Installer PHP 5.3.3 sur Wampserver</title>
		<link>http://www.shivato-web.com/blog/php/tuto-installer-php-5-3-3-sur-wampserver/</link>
		<comments>http://www.shivato-web.com/blog/php/tuto-installer-php-5-3-3-sur-wampserver/#comments</comments>
		<pubDate>Sun, 12 Sep 2010 11:39:07 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutoriel]]></category>
		<category><![CDATA[Wampserser]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=50</guid>
		<description><![CDATA[En utilisant en local sur Wampserver 2.0i (11/07/2009) avec PHP 5.3.0 (par défaut), une classe de session PHP réécrite pour fonctionner avec la base de données, dès que l’on déclare une nouvelle instance de la classe connexion dans la méthode write() de la classe session, tout le serveur se met à planter. Il s’avère que [...]]]></description>
			<content:encoded><![CDATA[<p>En utilisant en local sur <a href="http://www.wampserver.com">Wampserver</a> 2.0i (11/07/2009) avec PHP 5.3.0 (par défaut), une classe de session PHP réécrite pour fonctionner avec la base de données, dès que l’on déclare une nouvelle instance de la classe connexion dans la méthode write() de la classe session, tout le serveur se met à planter.<br />
Il s’avère que c’est la version de PHP qui génère le plantage du serveur. En utilisant la version 5.3.3 ou tout autre version que la 5.3.0 dans Wampserver, le serveur continue de tourner sans problème.</p>
<p><span style="text-decoration: underline;"><strong>Installer PHP 5.3.3 sur Wampserver :</strong></span></p>
<p>Quittez Wampserver.</p>
<p>Récupérez la version 5.3.3 sur le site <a href="http://windows.php.net/download/">http://windows.php.net/download/</a>, et téléchargez le pack VC6 x86 Thread Safe au format Zip.</p>
<p>Sur votre disque dur, dans le dossier où Wampserver est installé :</p>
<ul>
<li>Créez un dossier c:/wamp/bin/php/php5.3.3</li>
<li>Dézippez l’archive dans ce dossier, retirez le dossier extra</li>
</ul>
<p>Depuis le dossier c:/wamp/bin/php/php5.3.0, copiez les fichiers suivant vers php5.3.3 :<br />
- wampserver.conf<br />
- php.ini<br />
- phpForApache.ini</p>
<p>Remplacez dans php.ini :</p>
<pre class="brush: php; title: ; notranslate">extension_dir = &quot;C:/wamp/bin/php/php5.3.0/ext/&quot;</pre>
<p>par</p>
<pre class="brush: php; title: ; notranslate">extension_dir = &quot;C:/wamp/bin/php/php5.3.3/ext/&quot;</pre>
<p>&nbsp;<br />
Remplacez dans phpForApache.ini :</p>
<pre class="brush: php; title: ; notranslate">extension_dir = &quot;C:/wamp/bin/php/php5.3.0/ext/&quot;</pre>
<p>par</p>
<pre class="brush: php; title: ; notranslate">extension_dir = &quot;C:/wamp/bin/php/php5.3.3/ext/&quot;</pre>
<p>&nbsp;<br />
Redémarrez Wampserver, faites un clic gauche sur son icône dans la barre des tâches, allez dans PHP / Version et choisissez 5.3.3</p>
<p>Source : <a href="http://www.cmsmadesimple.fr/blog/index.php?post/2010/03/23/Installation-«-manuelle-»-de-PHP-5.3.2-avec-Wampserver">http://www.cmsmadesimple.fr/blog/index.php?post/2010/03/23/Installation-«-manuelle-»-de-PHP-5.3.2-avec-Wampserver</a></p>
<p>&nbsp;</p>
<p><strong>EDIT (06/11/2010) :</strong><br />
Si vous installez PHP 5.3.3 sur windows 7 (surement Vista aussi), il se peut que votre phpMyAdmin vous donne une page blanche.<br />
Pour y remédier, ouvrez Notepad (clic droit sur Notepad > Exécuter en tant qu’administrateur), ouvrez le ficher C:\WINDOWS\system32\drivers\etc\hosts.<br />
Décommentez la ligne "127.0.0.1 localhost" et commentez celle-ci si n'est pas déjà fait "::1 localhost".
</p>
<p>&nbsp;</p>
<p><span style="text-decoration: underline;"><strong>Bonus : Lancer Wampserver au démarrage de Windows 7 :</strong></span></p>
<p>Cliquez sur Démarrer puis entrez "Services" dans Rechercher</p>
<p>Cliquez sur l'application Services qui doit vous être proposée</p>
<p>Repérez les services wamapache et wampmysql, sur chacun d'eux, faites un clic droit, puis cliquez sur Propriétés.</p>
<p>Dans la boîte de dialogue qui s'ouvre, dans la partie "Type de démarrage", choisissez "automatique". Validez en cliquant sur OK.</p>
<p>Votre serveur démarre maintenant à chaque démarrage de votre ordinateur.</p>
<p>L’icône de Wampserver dans la barre des tâches est absent, il vous faudra démarrer Wampserver manuellement pour le configurer.</p>
<p><em>P.S. : Si vous trouvez une solution pour avoir l’icône dans la barre des tâches, n’hésitez pas à poster un commentaire.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/php/tuto-installer-php-5-3-3-sur-wampserver/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[BUG] Flux vidéo + Facebox sous Internet Explorer</title>
		<link>http://www.shivato-web.com/blog/javascript/bug-flux-video-dans-facebox-sous-internet-explorer/</link>
		<comments>http://www.shivato-web.com/blog/javascript/bug-flux-video-dans-facebox-sous-internet-explorer/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 07:58:28 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[JAVASCRIPT]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[BUG]]></category>
		<category><![CDATA[facebox]]></category>
		<category><![CDATA[Internet Explorer]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Vidéo]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=36</guid>
		<description><![CDATA[Si vous utilisez le plug-in jQuery facebox (version 1.2) pour y mettre des flux vidéo (dailymotion, youtube…), lorsque vous fermerez la lightbox avant la fin de la lecture de la vidéo, le son de celle-ci continuera d’être joué sous Internet Explorer. En effet le plug-in se contente de ne plus afficher la lightbox sans prendre [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.shivato-web.com/blog/wp-content/uploads/2010/07/facebox.png"><img class="aligncenter size-full wp-image-38" title="facebox" src="http://www.shivato-web.com/blog/wp-content/uploads/2010/07/facebox.png" alt="" width="300" height="269" /></a></p>
<p>Si vous utilisez le plug-in jQuery <a href="http://defunkt.github.com/facebox/" target="_blank">facebox</a> (version 1.2) pour y mettre des flux vidéo (dailymotion, youtube…), lorsque vous fermerez la lightbox avant la fin de la lecture de la vidéo, le son de celle-ci continuera d’être joué sous Internet Explorer.</p>
<p>En effet le plug-in se contente de ne plus afficher la lightbox sans prendre la peine de supprimer son contenu. Pour y remédier, il suffit d’ajouter 1 ligne de code à la fin du fichier facebox.js :</p>
<pre class="brush: jscript; title: ; notranslate">
$(document).bind('close.facebox', function() {
   $(document).unbind('keydown.facebox')
   $('#facebox').fadeOut(function() {
      $('#facebox .content').empty() //ligne à ajouter
      $('#facebox .content').removeClass().addClass('content')
      hideOverlay()
      $('#facebox .loading').remove()
   })
})
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/javascript/bug-flux-video-dans-facebox-sous-internet-explorer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[BUG] Colorpicker jQuery + Chrome 5</title>
		<link>http://www.shivato-web.com/blog/javascript/bug-colorpicker-jquery-chrome-5/</link>
		<comments>http://www.shivato-web.com/blog/javascript/bug-colorpicker-jquery-chrome-5/#comments</comments>
		<pubDate>Sat, 26 Jun 2010 19:25:25 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[JAVASCRIPT]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[BUG]]></category>
		<category><![CDATA[Chrome]]></category>
		<category><![CDATA[colorpicker]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=11</guid>
		<description><![CDATA[Au cours du développement d'un projet client, j'ai dû mettre en place un colorpicker. Mon choix s'est orienté sur le colorpicker jQuery de www.eyecon.ro/colorpicker/ (version du 23.05.2009) qui est plutôt complet. Au passage de la version 5 de Chrome, le submit des formulaires avec le colorpicker ne fonctionnait plus, au lieu d'envoyer le formulaire Chrome [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a href="http://www.shivato-web.com/blog/wp-content/uploads/2010/06/colorpicker.png"><img class="size-full wp-image-10 aligncenter" title="colorpicker" src="http://www.shivato-web.com/blog/wp-content/uploads/2010/06/colorpicker.png" alt="" width="375" height="194" /></a></p>
<p>Au cours du développement d'un projet client, j'ai dû mettre en place un colorpicker.<br />
Mon choix s'est orienté sur le colorpicker jQuery de <a href="http://www.eyecon.ro/colorpicker/" target="_blank">www.eyecon.ro/colorpicker/</a> (version du 23.05.2009) qui est plutôt complet.</p>
<p>Au passage de la version 5 de Chrome, le submit des formulaires avec le colorpicker ne fonctionnait plus, au lieu d'envoyer le formulaire Chrome sélectionne le premier input de la couleur hsb qui contient un nombre décimal.</p>
<p>Ce sont les décimaux des couleurs hsb qui posent donc problème, mais vous ne verrez pas de décimaux tout le temps, ça se produit à 2 moments :</p>
<ul>
<li>à l'initialisation du colorpicker si on définit une couleur en rgb ou hexa</li>
<li>quand on change les couleurs rgb ou hexa dans leurs champs input</li>
</ul>
<p>J'ai testé sur différents navigateurs (Chrome 4, Firefox, Safari, IE et Opera) et bizarrement il n'y a que sur Chrome 5 (Windows et Linux) que le bug apparaît.</p>
<p>Si vous ne voulez pas modifier le code source du colorpicker, voilà une solution possible, il suffit de prendre les valeurs hsb, les arrondir et les remettre à leur place.<br />
Ca sera plus clair avec du code :</p>
<pre class="brush: jscript; title: ; notranslate">
$(document).ready(function(){
var divColorpicker=jQuery('#divColorpicker');
//fonction qui arrondi le hsb
var roundHsb=function(hsb){
var h=jQuery('.colorpicker_hsb_h input',divColorpicker);
var s=jQuery('.colorpicker_hsb_s input',divColorpicker);
var b=jQuery('.colorpicker_hsb_b input',divColorpicker);
h.val(Math.round(h.val()));
s.val(Math.round(s.val()));
b.val(Math.round(b.val()));
}
//initialisation du colorpicker
divColorpicker.ColorPicker({
flat:true,
color:'78AD78',
onChange:function(){
//on arrondi à chaque changement de couleur
roundHsb();
}
});
//on arrondi la couleur mise à l'initialisation
roundHsb();
});
</pre>
<p><strong><span style="text-decoration: underline;">Petite astuce bonus :</span></strong><br />
Si vous voulez passer du colorpicker noir au gris, ouvrez le fichier colorpicker.css et modifier le chemin des images :</p>
<pre class="brush: css; title: ; notranslate">
/* Remplacer ces chemins */
background: url(../images/colorpicker_background.png);
background: url(../images/colorpicker_select.gif);
background: url(../images/colorpicker_indic.gif) left top;
background: url(../images/colorpicker_hex.png) top;
background-image: url(../images/colorpicker_rgb_r.png);
background-image: url(../images/colorpicker_rgb_g.png);
background-image: url(../images/colorpicker_rgb_b.png);
background-image: url(../images/colorpicker_hsb_h.png);
background-image: url(../images/colorpicker_hsb_s.png);
background-image: url(../images/colorpicker_hsb_b.png);
background: url(../images/colorpicker_submit.png) top;

/* par */
background: url(../images/custom_background.png);
background: url(../images/custom_select.gif);
background: url(../images/custom_indic.gif) left top;
background: url(../images/custom_hex.png) top;
background-image: url(../images/custom_rgb_r.png);
background-image: url(../images/custom_rgb_g.png);
background-image: url(../images/custom_rgb_b.png);
background-image: url(../images/custom_hsb_h.png);
background-image: url(../images/custom_hsb_s.png);
background-image: url(../images/custom_hsb_b.png);
background: url(../images/custom_submit.png) top;

/* sauf celui là, sinon vous n'aurez plus le carré principal des dégradés */
background: url(../images/colorpicker_overlay.png);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/javascript/bug-colorpicker-jquery-chrome-5/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>C&#8217;est parti pour l&#8217;aventure du blog !</title>
		<link>http://www.shivato-web.com/blog/divers/cest-parti-pour-laventure-du-blog/</link>
		<comments>http://www.shivato-web.com/blog/divers/cest-parti-pour-laventure-du-blog/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 19:28:14 +0000</pubDate>
		<dc:creator>shivato</dc:creator>
				<category><![CDATA[Divers]]></category>

		<guid isPermaLink="false">http://www.shivato-web.com/blog/?p=7</guid>
		<description><![CDATA[Bonjour à tous, Bienvenue sur mon premier blog, et oui il y a un début à tout J'y parlerai généralement de développement web, de solutions trouvées pour corriger un bug , des tutos que j'aurais pas trouver en français... Mais pour ce premier post, place à la détente avec ce court-métrage (PIXELS) qui résume bien [...]]]></description>
			<content:encoded><![CDATA[<p>Bonjour à tous,</p>
<p>Bienvenue sur mon premier blog, et oui il y a un début à tout <img src='http://www.shivato-web.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
J'y parlerai généralement de développement web, de solutions trouvées pour corriger un bug , des tutos que j'aurais pas trouver en français...</p>
<p>Mais pour ce premier post, place à la détente avec ce court-métrage (PIXELS) qui résume bien le monde d'aujourd'hui.</p>
<p><object width="480" height="277"><param name="movie" value="http://www.dailymotion.com/swf/video/xcy39n"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/xcy39n" width="480" height="277" allowfullscreen="true" allowscriptaccess="always"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.shivato-web.com/blog/divers/cest-parti-pour-laventure-du-blog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.790 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-02-20 05:19:54 -->
<!-- Compression = gzip -->
