Extension du BsHelper #1 : Timeline

Le BsHelper peut être étendu pour permettre des mises en forme originales.




Introduction

Cet article va présenter comment le BsHelper peut être utilisé pour créer des éléments réutilisables qui s'appuient sur Bootstrap. L'exemple utilisé est une timeline, tirée du site Bootsnipp.

Contrairement à d'habitude, le code de cet article ne sera pas intégré dans le BsHelper.


But du code

Imaginons que nous développons une application qui nécessite la mise en place d'une ou plusieurs timelines. Par exemple, pour mettre en forme des échanges chronologiques entre différents utilisateurs. Notre application imaginaire doit pouvoir présenter une timeline sur de nombreuses pages différentes. Il peut donc être intéressant, par soucis de réutilisabilité, de créer des fonctions permettant de gérer le code HTML de notre timeline, à la manière des fonctions du BsHelper.

Le code qui sera présenté ci-dessous n'est pas tiré directement du code de Bootstrap. Il pourrait donc être intégré dans un Helper différent, comme un TimelineHelper, permettant de gérer spécifiquement la mise en page et pourquoi pas des fonctionnalités propres aux timelines (ordonnancement des élements, tris, etc.). Mais pour cet article, nous allons nous concentrer sur la partie mise en forme et donc intégrer directement les fonctions dans le BsHelper.

Rendu de la timeline :


Timeline Bootsnipp


On remarque que cette timeline (qui est responsive au passage) se compose de différents éléments eux mêmes composés spécifiquement :

  • Un élément de la timeline peut être rattaché à une bulle de couleur sur la timeline
  • Un élément de la timeline a un titre
  • Un élément de la timeline peut avoir un sous titre
  • Un élément de la timeline peut être placé à gauche de la timeline, ou à droite.
  • Un élément de la timeline peut avoir un contenu divers

Essayons maintenant, en s'appuyant sur des choses existantes dans le BsHelper, de coder tout ça.


Création des fonctions

Tout d'abord, il faut prendre en compte que cette timeline a du CSS qui va avec. On peut donc soit intégrer ce CSS directement dans le fichier bootstrap.css ou alors créer un fichier timeline.css et l'intégrer de cette façon, dans son layout, grâce à la fonction css du BsHelper :


echo $this->Bs->css(array('app' , 'timeline'));
// app.css est, par exemple, le fichier css de votre application

Passons maintenant au code de la fonction timeline.

2 premières fonctions simples, permettant d'ouvrir et fermer la timeline. La première repose sur la fonction tag du HtmlHelper, pour gérer plus facilement les attributs, notamment id et class.


/**
  * Open a Bootsnipp type Timeline
  * @param array $options for the tag function of the HtmlHelper
  * @return string
  */
public function openTimeline($options= array()) {
	
	if(isset($options['class']))
		$options['class'] = 'timeline '.$options['class'];
	else
		$options['class'] = 'timeline';
	
	return parent::tag('ul' , null , $options);
}
	
/**
  * Close a Bootsnipp type Timeline
  * @return string
  */
public function closeTimeline() {
	return '</ul>';
}

Maintenant les fonctions pour créer les différents noeuds (node) et les options dont ils peuvent disposer.


/**
   * Open a Node from a Bootsnipp type Timeline
   * @param string $title (optionnal)
   * @param array $options
   * 				- id : the optionnal id of the node
   * 				- placement : left by default, set "right" to put it right
   * 				- icon : which Font Awesome icon use for the Node (need the both icone and color option to work)
   * 				- color : one class color of bootstrap (like warning, success, etc.) 
   * 				- subtitle : an optionnal subtitle after the title
   * @return string
   */
public function openNode($title = null , $options) {
		
	$optionsNode = array();
		
	// id ?
	if(isset($options['id']))
		$optionsNode['id'] = $options['id'];
		
	// Placement ?
	if(isset($options['placement']) and $options['placement'] == 'right')
		$optionsNode['class'] = 'timeline-inverted';
		
	// The li element of the Node
	$out = parent::tag('li' , null , $optionsNode);
		
	// Badge ?
	if(isset($options['icon']) and isset($options['color']))
		$out .= '<div class="timeline-badge '.$options['color'].'">'.$this->icon($options['icon'], array('fw')).'</div>';
		
	// The div element of the Node
	$out .= '<div class="timeline-panel">';
		
	// Title ?
	if($title != null) {
		$out .= '<div class="timeline-heading">';
		$out .= '<h4>'.$title.'</h4>';

		// Subtitle ?
		if(isset($options['subtitle']))
			$out .= '<p class="small">'.$options['subtitle'].'</p>';
				
		$out .= '</div>';
	}
		
	// Body
	$out .= '<div class="timeline-body">';
		
	return $out;
}
	
/**
  * Close a Node from a Bootsnipp type Timeline
  * @return string
  */
public function closeNode() {
		
	$out  = '</div>';
	$out .= '</div>';
	$out .= '</li>';
		
	return $out;		
}

Plusieurs choses intéressantes dans ce code.

Tout d'abord, on a défini le titre du noeud comme un paramètre important. Les autres paramètres sont facultatifs et on été mis dans un tableau d'options. Les fonctions des Helper de CakePHP fonctionnent souvent de cette façon et permettent d'être flexibles (ajout facile de nouvelles options, sans toucher à la déclaration de la fonction).

On gère donc les options une par une et on ajoute les éléments HTML au fur et à mesure.

On remarque également l'appel de la fonction icon qui avait été intégrée dans le BsHelper pour la sortie de Font Awesome 4.

En créant la fonction, nous avons hésité à ajouter un paramètre $content qui aurait permis de passer le contenu entier du noeud comme un paramètre de la fonction. Cela aurait aussi permis de ne pas avoir de fonction close. Cela peut être utile pour des cas simples, si on affiche simplement un texte dans chaque noeud mais devient moins pratique pour des cas complexes, avec un contenu plus "riche" dans le noeud (boutons d'actions, autres informations issues d'un autre modèle, etc.). Il aurait fallu concaténer tout ça avant de passer la variable à la fonction. Quelque chose comme ça :


$content = 'Debut noeud';
$content .= '' ; // Du nouveau contenu
$content .= '' ; // Du nouveau contenu
$content .= '' ; // Du nouveau contenu
$content .= '' ; // Du nouveau contenu
$content .= '' ; // Du nouveau contenu
$content .= '' ; // Du nouveau contenu
$content .= '' ; // Du nouveau contenu

echo $this->Bs->node('Un noeud', $content , array( 'icon' => 'edit' , 'color' => 'warning'));

Les deux variantes ont leurs avantages et leurs défauts au niveau du code, mais le rendu reste le même, à vous de choisir ce que vous préférez :)


Intégration dans une vue

// Fonctions du BsHelper pour gérer la grille de Bootstrap
echo $this->Bs->container().
      $this->Bs->row().
      $this->Bs->col('xs12' , 'sm9 of1');

// On ouvre la timeline
echo $this->Bs->openTimeline();

// premier noeud
echo $this->Bs->openNode('Première Node' , array('icon' => 'clock-o' , 'color' => 'success'));
echo '<p>Gummies jelly toffee sesame snaps bonbon jelly sweet roll cotton candy. Tiramisu lollipop tart I love I love. Unerdwear.com powder cheesecake marzipan I love.</p>';
echo $this->Bs->closeNode();

// second noeud
echo $this->Bs->openNode('Deuxième Node' , array('placement' => 'right' , 'icon' => 'edit' , 'color' => 'warning'));
echo '<p>Gummies jelly toffee sesame snaps bonbon jelly sweet roll cotton candy. Tiramisu lollipop tart I love I love. Unerdwear.com powder cheesecake marzipan I love.</p>';
echo $this->Bs->closeNode();

// On ferme la timeline
echo $this->Bs->closeTimeline();

// Fonctions du BsHelper pour gérer la grille de Bootstrap
echo $this->Bs->close(3);

Le code ci-dessus est assez simple. On gère la grille de Bootstrap, on ouvre la timeline puis on crée 2 noeuds, chacun avec des options différentes (couleur, icône, placement).

Rendu du code :


Timeline Bootsnipp


Aller un peu plus loin...

L'exemple de code ci-dessus permet de voir rapidement comment utiliser les fonctions nouvellement créées. Mais dans la réalité, on code rarement comme ça, peut être s'il y a un ou deux noeuds, mais dès qu'il y en a plus, on va souvent se trouver dans le cas où les données à afficher sont issues d'une base de données. Dans ce cas, on va donc se retrouver avec un nombre de données à afficher qui peut être conséquent et une boucle s'impose alors.

Prenons l'exemple suivant, nous souhaitons afficher tous les messages d'une conversation. Voici le modèle Message que nous allons utiliser :


On aurait alors un code qui ressemblerait à ça :

// On ouvre la timeline
echo $this->Bs->openTimeline();

// On définit une icône et une couleur par défaut pour tous les noeuds
$icon = 'envelope-a';
$color = 'success';

foreach($messages as $message) {
	
	// On se place ici dans le cas d'une application sécurisée par Auth
	// Avec un code de ce type là dans le AppController :
	// $this->set('currentUserId' , $this->Auth->user('id'));
	// Si je ne suis pas l'utilisateur courant, je mets le message à droite de la timeline
	if($message['Message']['user_id'] != $currentUserId)
		$placement = 'right';
	else
		$placement = 'left';
	
	// On crée le sous titre avec le nom de l'utilisateur et la date du message
	// On utilise les conventions classiques de CakePHP pour accéder au nom de l'utilisateur, considérant Message belongsTo User
	// On utilise le Helper Time pour formater la date
	$subtitle = $message['User']['name'].' | le '.$this->Time->format($message['Message']['created'] , 'd/m/Y');
	
	echo $this->Bs->openNode($message['Message']['title'] , array('icon' => $icon , 'color' => $color , 'placement' => $placement , 'subtitle' => $subtitle)).
		 '<p>'.$message['Message']['content'].'</p>'.
		 $this->Bs->closeNode();

}

// On ferme la timeline
echo $this->Bs->closeTimeline();

Selon les cas ce code pourrait, bien entendu, être complètement différent. On aurait par exemple pu gérer une importance à chaque message, en jouant sur l'icône et la couleur. Ou encore créer un "footer" pour chaque message qui contiendrait des boutons d'actions (supprimer, répondre, etc.).


Conclusion

On a donc vu dans cet article comment étendre le BsHelper à d'autres fonctionnalités qui ne sont pas forcément liées directement à Bootstrap. Le BsHelper peut donc être considéré comme une base de travail pour venir intégrer toutes les fonctionnalités qui seront liées à des mises en forme spécifiques et répétées au sein de votre design. Bien entendu, d'autres Helpers peuvent être créés si les fonctions nécessaires deviennent trop nombreuses et complexes et s'éloignent alors de la logique de base du BsHelper.

N'hésitez pas à réagir dans les commentaires sur cet article un peu différent des autres ou à nous proposer d'autres bouts de code (tirés par exemple de Bootsnipp) pour lesquels nous pourrions consacrer un autre article.




Suivez l'actualité de Web and Cow

Développement web ? Amélioration de son workflow ? Bonnes pratiques ? API tierces ? CakePHP ? Ce sont des thématiques qui vous parlent ? Abonnez vous à notre newsletter pour découvrir nos derniers articles ainsi que les produits du studio Web and Cow. 1 à 2 newsletters par mois.



Newsletter WAC


Aucun spam, désinscription à tout moment.






comments powered by Disqus





Vous avez un projet ? Contactez-nous.

Agence web basée à Rennes, nous avons aussi l'habitude de travailler à distance avec des gens situés à Paris, Lyon, Nantes, etc. Donc peu importe votre localisation ou l'avancement dans la réflexion de votre projet, laissez-nous vos coordonnées et nous vous recontacterons très vite pour en parler plus en détails.


4 bis allée du Bâtiment, 35000 Rennes
06.47.52.18.78     a.weill@webandcow.com