Planète

Par Marc Delnatte
Akabia

Retrouvez-nous au Nord It Days

L'agence Akabia est heureuse de vous retrouver le jeudi 17 avril prochain, lors de la 6ème édition des Nord IT DAYS, l'événement numérique incontournable de la région Nord-Pas-de-Calais.







Par GoZ
Fabien CLEMENT

Ajouter une propriété à une entitée

Je souhaitais pouvoir ajouter une propriété à une entité. Certainement fatigué au moment où j'ai pensé qu'il était indispensable de faire cela, j'ai bossé dessus une paire d'heures avant de me rendre compte, au moment où tout fonctionnait... que je n'en avais pas besoin finalement...

Histoire que ce ne soit pas perdu, je vais tout de même récapituler ce qu'il faut faire ici.

en lire plus

Par fgm@drupal.org
Frédéric G. Marand

Standardisation PHP : le groupe PHP-FIG et les standards PSR

Avec la montée progressive en niveau d'exigence des projets PHP, notamment dans les projets en entreprise comme les extranets et applications spécifiques, le rôle des frameworks et CMS devient prééminent et, avec leur poids, le besoin de coopérer sans devoir réinventer la roue dans chaque silo technologique: Symfony, Zend Framework, Drupal, et tous les autres.

Depuis 2009, le groupe PHP-FIG s'est fondé pour favoriser l'interopérabilité entre tous ces frameworks, CMS et grandes applications en définissant des standards permettant aux projets d'utiliser des composants à l'interface standardisée pour favoriser le mix and match des meilleurs outils dans chaque environnement. Parmi ces standards:

en lire plus

Par AlanT
Alan Tondelier

Personnalisez jusqu'à la moelle le template de vos field-collections

Troll matryoshka

Le module field_collections permet de créer des "champs de champs", particulièrement pratique pour accélérer la création de contenus et permettre de simplifier la gestion en back-office. Si vous avez déjà travaillé avec field-collection, vous avez pu vous heurter à un problème lors de la modification de la sortie HTML, ou bien essayé de "themer" différement un des items de votre field-collection. 
Cet article propose un template regroupant l'ensemble de la sortie html d'un field-collection, permettant ainsi d'en simplifier la personnalisation.

Note : Cet article est une réponse "simpliste" à un problème de la communauté Drupal datant du 14 Mai 2011 : https://drupal.org/node/1157794, actuellement la solution proposée n'a pas encore été implémentée. Elle le sera dans la version 2.x de field-collection qui rendra cet article obsolète.

Field Collection, anatomie d'un theming compliqué


Sortie par défaut de field-collection avec formatteur "Field collection items"

Lorsque vous mettez en place un field-collection, drupal va rendre l'html de sortie en passant par ces étapes :

  1. Ajout de l'html pour les variables (modifier/supprimer/ajouter) directement dans une fonction de theming interne au module field_collection,
  2. Passage au fichier de template field.tpl.php pour mettre en place l'html d'enveloppe du champ,
  3. Passage au fichier de template field-collection-item.tpl pour rendre l'html de chaque item de field-collection.

Donc, si je veux personnaliser entièrement la sortie html de mes field-collection , parce-que j'ai envie de faire une intégration html aux petits oignons, la mission va s'avérer assez délicate.

Une solution "maison"

Ce n'est pas la plus élégante des solutions !

Avant tout, la solution proposée n'a pas vocation de remplacer une vraie modification du coeur du module field-collection, bien au contraire, ce que je propose est à mi chemin entre un "hack" et une utilisation conventionnelle des fonctions de theming de Drupal. Aussi vous pouvez regardé du côté du topic officiel sur drupal.org pour un patch du module permettant (normalement) d'arriver au même résultat.
Cette solution a cependant l'avantage de faire le travail demandé, à savoir personnaliser au maximum la sortie de vos field-collection mais également d'être applicable sans aucune modification de module ou d'installations complémentaires ; en travaillant sur le template.php de votre thème et en modifiant deux fichiers .tpl.php.

Et dès que la version 2.x de field_collection sera sortie, le problème ne se posera plus.

En attendant...

Nous allons travailler dans template.php, remplacez "votre_theme" par le nom système de votre theme "front" :

template.php - hook_preprocess_node()

/**
 * Override or insert variables into the node template.
 */
function demo_preprocess_node(&$variables) {
  if ($variables['view_mode'] == 'full' && node_is_page($variables['node'])) {
    $variables['classes_array'][] = 'node-full';
  }

  // Field Collection Alter - This is required in order to pass the description of the field collection and the "add new item" to $variables.

  if (!empty($variables['content'])) {
    foreach ($variables['content'] as $key => $field) {

      if (isset($field['#field_type']) && $field['#field_type'] === 'field_collection' && $field['#formatter'] === 'field_collection_view') {

        // move description and links from #suffix into separate variables for field_collection_view;
          if ($field['#formatter'] === 'field_collection_view') {

            // remove #prefix - if not, get printed
            $variables['content'][$key]['#prefix'] = '';

            //capture links and description - this is hackish (but works) !
            preg_match("/<div .*>(.*)<\/div>./i", $field['#suffix'], $desc);
            preg_match("/(<ul.*<\/ul>)/i", $field['#suffix'], $links);

            // field_collection global description
            if (isset($desc[1])) {
             $variables['content'][$key]['fc_description'] = $desc[1];
            }

            // field_collection links (add new item to the collection)
            if (isset($links[1])) {
              $variables['content'][$key]['fc_links'] = $links[1];
            }

            //remove #suffix - if not, get printed
            $variables['content'][$key]['#suffix'] = '';

          }

      }

    }

  }
 
}

template.php - hook_preprocess_field

/**
 * Override or insert variables into the field template.
 */
function demo_preprocess_field(&$vars) {

  if (isset($vars['element']['#field_type']) && $vars['element']['#field_type'] === 'field_collection' && $vars['element']['#formatter'] === 'field_collection_view') {

    // move each item into a renderable array and pass html for edit and delete links into simple variables

    foreach ($vars['items'] as $key => &$item) {
      // item
      $item['item'] = array_shift($item['entity']);

      // edit
      if (isset($item['links']['#links']['edit'])) {
        $edit = $item['links']['#links']['edit'];
        $edit = l($edit['title'], $edit['href'], array('query' => $edit['query'],'attributes'=>array('class'=>'field-collection-edit-item')));
        $item['item']['#edit_link'] = $edit;
      }

      // delete
      if (isset($item['links']['#links']['delete'])) {
        $delete = $item['links']['#links']['delete'];
        $delete = l($delete['title'], $delete['href'], array('query' => $delete['query'],'attributes'=>array('class'=>'field-collection-delete-item')));
        $item['item']['#delete_link'] = $delete;
      }

      // pass a nice, renderable array to template file
      $item = $item['item'];

    }

    // add field-collection description
    if (isset($vars['element']['fc_description'])) {
      $vars['fc_description'] = $vars['element']['fc_description'];
    }
    
    // add field-collection links
    if (isset($vars['element']['fc_links'])) {
      $vars['fc_links'] = $vars['element']['fc_links'];
    }

  }
}

Ainsi, nous avons modifié les données transmises au fichiers templates. Les fichiers templates utilisés pour rendre les field-collection n'ont pas changé, il s'agit toujours de field.tpl.php pour l'enveloppe et field-collection-item.tpl.php pour chaque item de la collection. Or avec ce qui a été fait dans template.php, field-collection-item.tpl.php doit renvoyer la plus simple des structure (ie ne pas ajouter d'html).

field-collection-item.tpl.php - à placer dans votre thème

<?php
  print render($content);
?>

Maintenant la partie qui nous intéresse le plus, le template de rendu de votre field-collection : field.tpl.php. Si vous avez suivi le code, vous avez du voir que nous avons rendu disponible le contenu normalement affiché dans field-collection-item directement au niveau de field.tpl.php.

Votre template field.tpl.php est utilisé pour rendre l'html de tout les champs de votre site, vous cibler uniquement les field-collection, nommez le field--field-collection.tpl.php, vous pouvez également mettre différents templates par field-collection et par affichage selon la syntaxte :

  1. field--[nom_systeme_du_field].tpl.php
  2. field--[nom_systeme_du_field]--[nom_systeme_affichage].tpl.php

field--field-collection.tpl.php - à placer dans votre thème

<!-- field-collection wrapper -->
<div class="field-collection">

<?php if (!empty($fc_description)): // description of the field-collection ?>

  <div class="field-collection-description">

    <?php print $fc_description; ?>

  </div>

<?php endif; ?>

<?php foreach ($items as $delta => $item): // loop on each item of the collection ?>

  <div class="field-collection-item">
    <?php
      print render($item);
      // or play with some fields
      // print render($fc_item['my_field']);
    ?>

    <?php if (isset($item['#edit_link']) || isset($item['#delete_link'])): // check that links are available (can be enabled/disabled in display settings) ?>

      <div class="field-collection-item-links">
        <?php print isset($item['#edit_link'])?$item['#edit_link']:NULL; ?>
        <?php print isset($item['#delete_link'])?$item['#delete_link']:NULL; ?>
      </div>

    <?php endif; ?>

  </div>

<?php endforeach; ?>

  <?php print !empty($fc_links)?$fc_links:NULL; // link for adding a new item to the collection ?>

</div>
<!-- end field-collection wrapper -->

Videz vos caches, et normalement votre nouveau template prend le relai dans l'affichage de vos field-collections. À noter que ce template est utilisé uniquement lors de l'affichage "field collection items".


Veillez à mettre le format de sortie sur "field collection items", sinon le template par défaut sera utilisé.

J'espère que cet article vous sera utile, et n'hésitez pas à faire des retours si vous l'implémentez dans vos projets Drupal :)

Par Artusamak
Julien Dubois

Drupal Dev Days Szeged 2014 – Episode 3

Toutes les bonnes choses ont une fin, les Dev Days n’y font pas exception. Après vous avoir raconté ce à quoi j’ai participé au cours de la première journée et de la deuxième journée de la conférence à Szeged, voilà ce que j’ai retenu de ma dernière journée.

Marvin assis devant un micro

Marvin se prépare à donner sa session (c) Mr.TeeCee

The future of media management in Drupal 8

Démarrage de la journée par cette présentation, je suis un peu curieux de savoir ce qu’il se trame pour D8 sachant que je sors d’un projet où nous avons dû gérer des médias. La session est présentée par Janez Urevc, ses slides sont disponibles sur son site. Sauf qu’en fait le chantier n’est pas hyper avancé, des discussions ont lieu depuis Prague mais sont un peu bloquées faute d’accord sur la direction dans laquelle aller. Du coup si des bonnes volontés veulent aider, rejoignez les issues, la conversation doit avancer.

Develop for D8 on D6 and D7

Ensuite direction la présentation de FGM qui a donné son point de vue sur la bascule vers Drupal 8. Il s’appuie sur des expériences passées pour décrire les situations à préférer pour faire du D8 ou non. Tout n’était pas hyper clair pour moi, j’attends ses slides pour résumer sa pensée et donner mon avis. (Il était trop tôt pour moi :)).

Graph databases for D8

Cette session a été la session de la conférence pour moi. J’avais découvert ce qu’étaient les graph databases lors des Human Talks de Paris (rendez-vous tous les deuxième mardi du mois pour venir nous voir) et Peter Arato nous a fait une présentation de Neo4j, une solution en Java, pendant 40 minutes en expliquant les usages que l’on pouvait en tirer. Comme tweeté en sortant de la salle :

Le constat est simple, lorsque vous cherchez à afficher les résultats de requêtes complexes telles que « liste les amis, des amis de mes amis » les bases de données relationnelles ne sont pas compétitives, par design elles ne sont pas faites pour ça. L’idée est donc de stocker les données différemment. Et c’est là que les graph databases apportent leur solution, au lieu de normaliser les entrées en ajoutant des clés pour faire des jointures vous décrivez les relations entre les éléments. Exemple : John / cuisine pour / Lisa, John / habite / Londres, Lisa / habite / San Franciso, John / aime / Lisa. En multipliant les relations entre les objets vous obtenez un réseau de connexions. Le principe suivant est que lorsque vous allez requêter votre base de données vous allez définir un point de départ, décrire les conditions de relations que vous voulez poser, leur profondeur et potentiellement le type de connexions attendues. Exemple : « Trouve moi une fête où il y aura au moins 20 de mes amis proches qui ne connaissent pas mon ex ». C’est très « naturel » comme langage, si vous regardez la syntaxe des requêtes vous verrez que c’est très lisible.
Quel intérêt à utiliser ce genre de base de données ? Non, elles ne remplaceront pas totalement un MySQL pour le moment, l’idée est plutôt de s’appuyer sur ce type de bases pour faire les calculs complexes et laisser MySQL servir la page de détails d’un résultat de recherche par exemple. Les tendances du web sont à la recommandation et à la personnalisation, c’est tout à fait approprié d’avoir un index à côté du site principal à partir duquel on extraira les résultats de ces calculs avancé (à la Solr).
Le niveau d’intégration avec Drupal est très basique, il y a la possibilité d’indexer des données, quelques types de champs sont supportés et il est faisable de requêter depuis une fenêtre le serveur Neo4j sans aller plus loin pour l’instant.
Les slides de Peter sont en ligne, allez y jeter un oeil et intéressez-vous au sujet, vous en entendrez de plus en plus parler, tout comme les bases de données document.

Configuring D8

L’un des nouveaux morceaux très attendus de Drupal 8 est l’intégration dans le core d’un outil pour l’industrialisation, un remplaçant de Features. Un système permettant d’exporter et d’importer de la configuration d’un environnement à un autre. Gabor s’est dévoué pour remplacer Alex Pott souffrant pour la présentation. En gros le meilleur moyen que vous plongiez dans le système est de le manipuler. La page de documentation de l’API de configuration est une lecture obligatoire pour plonger dans ce nouveau morceau. Il a été pensé pour permettre d’éviter les problèmes connus de Features et permettre de facilement générer des diffs, facilement s’interfacer avec le multilinguisme et facilement être déployable.
Il faudra juger à l’usage, mes premiers tests pour le portage de Views Megarow m’ont paru satisfaisants. Sachez que la configuration est stockée sous forme de Yaml maintenant et que le bon vieil adage Don’t hack core est devenu Don’t hack your active config car cela peut faire exploser votre site assez facilement si vous le bidouillez.
Pas de slides à disposition, lisez la page de documentation, vous découvrirez entre autres qu’il y a plusieurs niveaux de configuration, la configuration « simple », que vous stockiez avant via un variable get / set et les configurations « complexes » qui introduisent le concept de config entities.

D8 for real

Dernière présentation de la dernière journée et dernier speaker que j’aime beaucoup, Florian. Il nous partage son point de vue sur l’état de Drupal 8 et ce que l’on peut faire avec dès maintenant. Il dresse un constat de ce qui va évoluer dans nos façons de faire les projets avec un ratio d’utilisation des modules contrib qui devrait baisser comparé à Drupal 7 compte tenu du fait que chaque nouvelle version majeure rend le produit de plus en plus utilisable out of the box.
Mais Florian ne s’arrête pas là, il pointe du doigt le fait qu’avec tous les changements apportés au coeur les modules les plus populaires devraient être réécrits pour profiter de la nouvelle façon dont Drupal fonctionne. Et quitte à réécrire un module, peut être qu’il faut complètement ré-envisager la façon dont on s’en sert. Il s’appuie pour cela sur l’exemple de Panels, avec toutes les technos qui sont apparues ces dernières années, peut être qu’il sera possible de faire un outil répondant à nos besoins d’une façon complètement nouvelle. Ou peut être que l’on n’aura pas besoin de Panels du tout maintenant !
L’important c’est que les gens commencent à se servir de Drupal 8 pour qu’il monte en puissance très vite. Si vous souhaitez être un acteur significatif de l’éco-système il est crucial que vous vous y intéressiez plus tôt que tard. En construisant de vrais projets, en utilisant Drupal 8 pour de vrai, vous identifierez des besoins et proposerez des solutions qui seront peut être les Panels de demain.

Par Artusamak
Julien Dubois

Drupal Dev Days Szeged 2014 – Episode 2

Les Drupal Dev Days ce sont trois jours de conférence, si vous voulez savoir ce qu’il s’est dit précédemment, n’hésitez pas à lire mon compte-rendu de la première journée des Drupal Dev Days Szeged. Voilà ce que j’ai retenu de la deuxième journée.

Drupal Developer Days - J2

Keynote

Pour continuer sur leur lancée, les organisateurs ont proposé une Keynote avec un intervenant de qualité, en l’occurence une intervenante car il s’agissait de Cathy Theys (@YesCT sur drupal.org). Le sujet de sa présentation était à propos de l’organisation de sprints. Cathy est l’une des figures incontournables lorsque l’on parle de sprints, elle a aidé à se former des sprints allant de 10 personnes à plus de 600.

Les messages qu’elle a envoyé lors de son intervention sont assez simples, pour réussir vos sprints les nouveaux arrivants sont la clé. Il y a un cercle vertueux à les mentorer efficacement. Un débutant est impressionné par toute la mécanique du développement du coeur alors prenez le par la main en l’aiguillant vers des issues qui sont à sa portée pour le mettre en confiance. Prenez également le temps de faire du suivi avec ces nouveaux venus pour qu’ils ne soient pas lâchés dans la nature.
La principale difficulté consiste à réussir à « fidéliser » les contributeurs, trop souvent ils viennent aider pendant 1 ou 2 jours puis repartent dans la nature. Si vos sprints sont bien gérés, vos mentors vont prendre soins de ces nouveaux arrivants et pourront petit à petit les aider à devenir eux même mentors.
Être mentor n’est pas une mission réservée à une élite, si vous avez appris à faire une chose vous pouvez la réapprendre tout de suite à quelqu’un d’autre (et vous devenez alors son mentor). Les mentors peuvent ne pas savoir et vont vous transmettre leur approche pour trouver des réponses « voilà comment je m’y prendrais pour chercher », « j’irais parler à cette personne pour lui demander son avis », etc.
C’est grâce à l’envie de partager que la communauté fonctionne et que les sprints prennent chaque année un peu plus d’ampleur. Ne soyez donc pas effrayés et tentez de proposer un coup de main autour de vous en organisant vos sprints. Même si les gens ne viennent pas en masse la première fois, martelez vos messages, continuez de laisser une porte ouverte pour permettre aux plus timides de sauter le pas et la sauce prendra autour des sprints.
Par ici pour lire ses slides.

Building really fast websites with D8

Ma première session de la journée a été celle de Wim Leers, il y a parlé des performances de notre cher Drupal et de comment l’on pouvait les améliorer. La session était principalement orientée autour des problématiques de cache et bien entendu des problèmes d’invalidation de cache (l’un des deux sujets les plus compliqués en informatique avec le nommage des choses). L’un des principaux problèmes du cache généré par D7 est que le markup de certains éléments comme les liens contextuels, ou l’affichage d’un drapeau « nouveau contenu » change d’un utilisateur à l’autre, obligeant à générer autant de variantes d’un même cache. Changer de technique pour cacher ces données est donc une piste qui a été suivie, l’idée consiste à générer la même base de markup pour tous et d’injecter des placeholders qui sont remplacés à la volée pour chaque utilisateur. Cela coûte quelques requêtes supplémentaire par page mais cela est beaucoup plus bénéfique dans son ensemble. S’appuyer sur des techniques comme le localStorage / sessionStorage (stockage de données côté client plutôt dans une base de données) fait aussi parti des nouvelles façons de faire qui permettent de rendre la gestion du cache plus maligne.
Dans Drupal 8, il était impossible de savoir quels caches invalider lorsqu’un contenu était mis à jour, il y avait le cache du rendu direct de l’entité mais peut être aussi des rules ou des pages de listing à invalider. Difficile donc de savoir qu’est ce qui était utilisé où.
Il a donc été décidé d’ajouter des tags aux bins de cache, permettant ainsi de tagger un élément avec un node id, un user id ou un type de contenu (mais pas que), de cette façon lorsque vous allez invalider un cache, vous allez invalider un tag « je veux vider tous les caches qui sont liés au node 2254″. Imbattable comme technique pour améliorer la finesse des invalidations !
La présentation était vraiment intéressante, les slides ne sont pas encore en ligne mais je mettrai l’article à jour si je parviens à mettre la main dessus.

D8 plugin system

Un des gros morceaux de Drupal 8 a été présenté par Aspilicious. Le système de plugin de Drupal 8 pourrait être présenté de plein de façons différentes et avec des degrés de profondeur plus ou moins importants. Je vais me contenter de vous en faire la description qui me parait la plus pertinante.
Le système de plugin se base sur le principe des annotations introduit par un composant de Symfony. Les annotations sont des commentaires autour des classes qui suivent une structure bien définie et qui permettent au système d’étendre les composants de votre application. C’est ni plus ni moins que l’équivalent de vos hook_info_*() dans Drupal 7.
Le système de plugins en lui même est la possibilité qu’il vous est donnée de créer vos propres composants, vos propres hook_info(). Jetez un oeil aux slides, Aspilicious a pris le temps d’introduire tous les concepts de la plugin API par une suite d’exemples de plus en plus complexes.

Themer VS Coder

Moment de légèreté de la journée, Campbell et Adam, développeur pour l’un et thémeur pour l’autre, sont partis d’une base de wireframe de site et se sont donné comme mission de s’approcher de la mise en page demandée au plus près en partant d’un site Drupal avec des contenus déjà saisis et un peu de configuration faite.
Après 15 minutes chacun, on se rend compte que certaines choses sont faciles à faire pour l’un des deux mais plus compliquées pour l’autre (et inversement).
La conclusion de leur démo (où ils arrivent presque tous les deux au résultat demandé) est que tous les corps de métier doivent collaborer car leurs compétences sont complémentaires.

Get ready for fully translated sites with Entity Translation

Schnitzel impliqué dans l’équipe multilingue qui travaille sur Drupal 8 a présenté l’état de l’art des traductions pour Drupal 7. Il n’est pas toujours simple de choisir sa stratégie de traduction de contenu mais ça l’est un peu si vous lisez les slides de la présentation. Michael a montré comment utiliser Entity Translation et comment basculer vers ce module si précédemment vous utilisiez content translation ou field translation. Ce module est une référence et a été utilisé dans la nouvelle version majeure de Drupal. Ses slides sont en ligne (attention aux allergiques, beaucoup de chatons dans les slides !)

Care for your backoffice

Cette dernière présentation de la journée est celle que Guillaume et moi avons donné, les slides sont ci-dessous. Pendant cette présentation nous avons listé les conseils et modules que vous pouvez utiliser pour améliorer vos backoffice. Des utilisateurs passent des heures à se servir de ces interfaces, optimisez les, profitez de modules disponibles côté contrib pour rendre vos backoffices plus utilisables et si vous avez de bonnes idées, contribuez les !

Par hellosct1

Rendez-vous en conférence avec @afup_paris

L'AFUP Paris est l'antenne Parisienne de l'Association Française des Utilisateurs de PHP (AFUP). Le fonctionnement de celle-ci est d'alterné les apéros PHP et les rendez-vous.

Le 2 avril 2014, salle Spark (Paris), nous organisations un rendez-vous sous le thème : 'Intéropérabilité des frameworks PHP'.

Le programme de cette soirée :

  • Ouverture des portes à 18h30
  • 1ere présentation : les containers d’injection par David Négrier de The Coding Machine
  • 2ème présentation : Les efforts de FIG par Frédéric Marand de Osinet
  • 3ème présentation : présentation surprise
  • Pot de l’amitié

Alors venez nombreux pour parler de ce sujet et nous voir

J'en profite pour remercier l'ensemble des sites qui ont relayés l'informations : AFUP, AFUP Paris, Toolinux, Linuxfr, Agendadulibre

Bien entendu, vous pouvez toujours vous inscrire à cette soirée à partir du lien suivant : http://afup.org/pages/rendezvous/index.php?id=20

Par Artusamak
Julien Dubois

Drupal Dev Days Szeged 2014 – Episode 1

Voilà que la première journée de conférence des Drupal Dev Days 2014 se termine.  Moins d’un an après l’édition de Dublin, la communauté des développeurs Drupal se retrouve à Szeged (Hongrie) pour son rendez-vous préféré.

Photo de groupe pour les Drupal Dev Days 2014 à Szeged (Par mr.TeeCee)

Photo de groupe pour les Drupal Dev Days 2014 à Szeged (Par mr.TeeCee)

La conférence se déroule sur toute la semaine avec depuis lundi (et même dimanche soir) des journées de sprint. L’idée est de profiter de ces moments ensemble pour faire plusieurs choses : aider des nouveaux contributeurs à mettre le pied à l’étrier (presque 2 000 contributeurs déjà impliqués pour Drupal 8), échanger de vive voix entre contributeurs core afin de débloquer certains points, ou tout simplement découvrir Drupal 8.
Les sujets sont divers et variés, on y trouve par exemple du débuggage pour le site drupal.org, la gestion du multilinguisme, le thèming autour de Twig, la résolution des beta blockers, etc.

Keynote

A propos du contenu, le coup d’envoi de la journée a été donné par Jam lors d’une keynote dédiée à Drupal 8, il  a profité de sa tribune pour rendre hommage aux contributeurs déjà impliqués et a invité les nouveaux venus à s’impliquer également. Il y a du travail pour tous les niveaux et si vous ne savez pas à qui parler la technique qu’il a recommandé est très bonne : « Vous tendez votre bras et pointez votre doigt devant vous, vous fermez les yeux et faites trois tours sur vous même. En rouvrant les yeux vous parlez à la personne que pointe votre doigt et lui demandez comment contribuer, il y a de fortes chances qu’elle sache vous dire quoi faire ou vers qui vous tourner. »

Entity API pour Drupal 8

Après cette keynote Fago a pris le relai pour présenter entity API pour Drupal 8. Quoi de neuf au programme ? L’entity API dans sa version pour Drupal 7 n’était pas terminée, elle a donc été unifiée, réécrite, optimisée.
Changement le plus notable, les propriétés et les champs sont maintenant tous des champs. Ils sont respectivement des base fields et des bundle fields. Cela signifique que manipuler des propriétés ou des champs se fera de façon transparente, les mêmes méthodes pourront être appelées. Autre bénéfice, on peut donc maintenant appliquer des formateurs et des widgets aux base fields (anciennement appelés propriétés) et c’est une très bonne nouvelle !
Obtenir des informations sur le modèle des données se résume à appeler une simple méthode là où avant il fallait appeler un hook_entity_info() et faire pas mal de navigation au sein du tableau de données retourné.
J’ai aimé ses explications sur la validation API qui prend tout son sens lorsque vous faites du REST, vous ne pouvez pas valider vos données comme si un formulaire venait d’être soumis, il vous faut donc vous appuyer sur une autre logique de validation, et c’est là que la validation API entre en jeu.
Prenez le temps de parcourir les slides, il y a beaucoup d’informations très intéressantes, on y parle du stockage, de la façon de définir de nouveaux types d’entités, de contrôle d’accès etc.

Point sur les initiatives non officielles

Pour la deuxième session de la journée, je suis allé voir Pedro nous partager ce qu’il se passe du côté des initiatives « non officielles » pour Drupal 8. Il s’agit de changements plus ou moins grands portés par quelques individus qui continuent de rendre Drupal meilleur. En vrac, il a parlé de WYSIWYG, Twig, Menus comme entités, de l’introduction des form modes (yay \o/), de la nouvelle façon de faire la migration et de plein d’autres sujets. Jetez un oeil à ses slides elles valent le coup et vous découvrirez sûrement pas mal de nouveautés pour Drupal 8.

D8: Fields reborn

A la reprise des sessions suite  à la pause déjeuner, Swentel a donné sa présentation sur le nouveau fonctionnement des champs pour Drupal 8. Le sujet a été rapidement évoqué par Fago dans sa session sur Entity API mais Kristof est allé plus loin. Il y a beaucoup de choses spécifiques détaillées dans ses slides et il sera bien plus intéressant pour vous de les consulter.

Cracking Drupal

La bonne surprise de la journée a été la présentation de Klausi sur la sécurité. Je m’attendais en rentrant dans la salle à écouter encore une session sur la sécurité qui était abstraite et pas vraiment appliquée à Drupal et ça n’a pas été le cas du coup. Klausi a pris le temps de vulgariser les principales failles de sécurités identifiées sur les sites et de faire un parallèle pour Drupal avec des exemples concrets.

Drupal and Scrum from the trenches

Cette session a été plus particulière, je n’y ai pas assisté, je l’ai donnée avec Guillaume. Nous avons partagé nos retours d’expériences sur Drupal et Scrum, vous pouvez accéder aux slides de notre présentation « Drupal and Scrum from the trenches » pour lire ce que nous avons présenté.

JS Pulp Fiction

Pour terminer les sessions de ce jour 1, direction la salle principale pour écouter nod_ nous parler de Pulp Fiction et de l’état de Javascript dans Drupal 8. Ses messages étaient autour des bonnes pratiques, de la nouvelle façon de travailler avec Javascript et de l’avenir potentiel du sujet.

La suite demain après une courte nuit de sommeil !

Par hellosct1

AgoraCMS j-30

Dans 30 jours se déroulera AgoraCMS 2014. Cette deuxième édition se déroulera le 25 avril 2014 à Paris à destination de l'ensemble des CMS : Drupal, Wordpress, Typo 3, Joomla, etc...

Ce rendez-vous est ouvert à toutes les personnes qui n’intéresses aux CMS en générales, mais aussi, aux DSI, chefs de projets technique et marketing.

Le thème principal de l'édition 2014 est 'Développez votre audience : du marketing à la technique'.

Le programme vient d'être publié avec 3 salles en parallèle :

  • E-marketing
  • Ergonomie/design
  • Technique

De plus, une salle découverte est en place pour découvrir les possibilités des CMS.

Enfin, les inscriptions sont ouvertes, et il est important de s'inscrire rapidement avant la fermeture du guichet.

Programme de AgoraCMS 2014

Site officiel de AgoraCMS

Par admin

Assemblée générale extraordinaire du 2 avril 2014

Fichier attaché Taille
dff-ag-2014-2.pdf 73.64 Ko

Chers adhérents,
J’ai le plaisir de vous convier à une assemblée général extraordinaire de notre association le mercredi 2 avril prochain, conformément à l’article 8 des statuts.
Cette réunion se tiendra le mercredi 2 avril 2014 à partir de 19h à la Maison des Associations du 3ème, 5 rue Perrée, 75003 Paris, dans la salle 1.
. Cette assemblée extraordinaire fait suite a celle organisée le 18 mars 2014 qui n’a pas réunit le quorum nécessaire au vote sur la modification des statuts de notre association. Conformément à l’article 8.2 nous convoquons une nouvelle assemblée générale extraordinaire. Celle-ci aura pour objet la soumission au vote de modifications de nos statuts, notamment sur la constitution du conseil d’administration et sur son mode de scrutin.
Si vous ne pouvez être physiquement présent lors du vote, vous pouvez vous faire représenter par un autre membre de l’association muni d‘un pouvoir régulier (ou vous pouvez l’envoyer à l’adresse de l’association au minimum 4 jours avant l’assemblée générale).
Vous pouvez également participer à l'assemblée générale par un moyen de communication électronique permettant de vous identifier formellement. Dans ce cas, si vous souhaitez participer aux votes vous devrez renoncer à l'anonymat des votes afin de les transmettre.
Je vous rappelle également que seuls les membres à jour de leur cotisation peuvent participer à l’assemblée générale et participer au vote, n'hésitez pas à adhérer dés à présent grâce au bulletin d'adhésion en ligne http://drupalfr.org/sites/default/files/formulaire-adherent-drupalfr.pdf ou sur place le jour même.

Olivier Friesse
Président sortant Drupal France & Francophonie

En page d'accueil : 
Par admin

Le nouveau bureau ADFF élu pour 2014 !

Lors de l'assemblée générale ordinaire du 18 mars 2014, les membres de l'association ont élu le nouveau bureau.

Voici les résultat du scrutin :

  • Anne Sophie Picot : 34 (élue)
  • Alexandre Israël : 7
  • Christophe Villeneuve : 27 (élu)
  • Edouard Cunibil : 33 (élu)
  • Florent Torregrosa : 23 (élu)
  • Frédéric G. Marand : 31 (élu)
  • Julien Dubreuil : 32 (élu)
  • Léon Cros : 35 (élu)
  • Olivier Pierre : 30 (élu)
  • Simon Morvan : 29 (élu)
  • Vincent Maucorps : 25 (élu)
  • Viriginie Jarosik : 28 (élue)

Le bureau se réunira dans le courant de la semaine prochaine pour désigner en son sein les nouveaux président, trésorier et secrétaire de l'association.

En page d'accueil : 
Par AlanT
Alan Tondelier

Simplifiez et accélérez vos installations Drupal avec Drush make

Drush est un outil en ligne de commande permettant d'administrer simplement Drupal. Disponible sur toutes les plateformes (unix/osx/windows), il est un indispensable du développement de vos sites.

La commande make de Drush permet de préparer rapidement une installation de Drupal avec ses modules contribués, ses librairies pré-téléchargées et plus encore. Incontournable quand on travaille sur un grand nombre de projets où l'on utilise à 80% les mêmes modules.

Une installation Drupal prête à l'emploi

C'est quoi Drush make ?

La commande drush make permet de récupérer les sources de projets Drupal (core, module, themes...) à partir des dépots officiels. Afin de décrire quels éléments récupérer, la commande make doit être accompagnée d'un fichier .make. Description et exemple d'un fichier .make :

mydrupal.make

; Base Drupal
core = 7.x

; Internal API for Drush make
api = 2

; Drupal Version
projects[drupal][version] = "7.26"

; Modules
; If no version precised, fetch the last stable one
; see projets[views] for an example

projects[admin_menu][subdir] = "contrib"
projects[adminimal_admin_menu][subdir] = "contrib"
projects[backup_migrate][subdir] = "contrib"
projects[ctools][subdir] = "contrib"
projects[ckeditor][subdir] = "contrib"
projects[ckeditor_link][subdir] = "contrib"
projects[context][subdir] = "contrib"
projects[devel][subdir] = "contrib"
projects[google_analytics][subdir] = "contrib"
projects[jquery_update][subdir] = "contrib"
projects[libraries][subdir] = "contrib"
projects[metatag][subdir] = "contrib"
projects[pathauto][subdir] = "contrib"
projects[pathologic][subdir] = "contrib"
projects[token][subdir] = "contrib"
projects[transliteration][subdir] = "contrib"
projects[variable][subdir] = "contrib"

; Declare the use of version 3.6 of views
projects[views][subdir] = "contrib"
projects[views][version] = "3.6"
projects[webform][subdir] = "contrib"

; Themes
projects[adminimal_theme][type] = "theme"
projects[mothership][type] = "theme"

; Libraries
; Please fill the following out. Type may be one of get, git, bzr or svn,
; and url is the url of the download.

libraries[lessphp][download][type] = "file"
libraries[lessphp][download][url] = "http://leafo.net/lessphp/src/lessphp-0.4.0.tar.gz"
libraries[lessphp][directory_name] = "lessphp"
libraries[lessphp][type] = "library"

libraries[ckeditor][download][type] = "file"
libraries[ckeditor][download][url] = "http://ckeditor.com/online-builder/releases/minified/4.3.3/moono/4.3.3/ckeditor_4.3.3.zip"
libraries[ckeditor][directory_name] = "ckeditor"
libraries[ckeditor][destination] = "modules/contrib/ckeditor"

Comme vous pouvez le voir la structure est très simple. Le fichier commence par déclarer la version de Drupal à utiliser, liste les projets eque vous souhaitez automatiquement télécharger ainsi que les thèmes. Les fichiers .make peuvent également récupérer directement les librairies dont vous avez besoin. 

Une fois ce fichier créé et enregistré, il vous suffit d'invoquer Drush avec cette syntaxe :

drush make mydrupal.make mywebsite -y

Drush créera votre installation de Drupal dans le dossier mydrupal, le switch -y répondra par l'affirmative à tous les prompts de la console.

Drush make console
Sortie de drush make sur un environnement windows

Le téléchargement des fichiers terminé, vous vous retrouvez avec votre dossier Drupal prêt à l'utilisation, vous n'avez plus qu'à executer install.php.

Pour une liste exhaustive des fonctionnalités de drush make, vous pouvez lire la documentation officielle (en anglais) ici

Drush make VS profil d'installation

Il est légitime de se poser la question : "Pourquoi ne pas passer par un profil d'installation Drupal ?"

Les fichiers make possèdent un certain avantage face aux profils d'installation :

  1. Vous récupérez automatiquement la dernière version stable du module,
    Tout en gardant la possibilité de préciser la version d'un module en particulier en rajoutant la ligne "projects[nomprojet][version] = "7.2", où 7.2 est la version de votre module.
  2. Il est plus facile de maintenir un fichier make qu'un ensemble de dossiers de modules, de plus vous pouvez facilement mettre en place des fichiers make pour chaque typologie de projets : site_corporate.make, site_multilingue.make, site_vitrine.make ...
  3. L'utilisation de drush make permet d'automatiser facilement le déploiment de Drupal dans des scripts bash (unix) ou batch (windows). J'y reviendrai.

Le principal point noir de Drush make est sa relative lenteur pour récupérer les fichiers des serveurs Drupal, là où un profil d'installation possède déjà tous les fichiers à installer.

Générer facilement ses fichiers .make

La méthode manuelle & semi-manuelle

Pour générer vos fichiers .make, vous pouvez simplement ouvrir votre IDE favori et taper à la main le fichier. À préférer lorsque vous savez exactement ce que vous voulez.

Une autre façon de faire est d'utiliser le site http://drushmake.me qui vous assistera dans la création de vos fichiers .make. Pratique !

Génération du .make à partir d'un site Drupal existant

Vous avez un site Drupal "référence" et vous souhaiteriez en sortir un fichier .make ? C'est possible !
Avec drush, placez vous dans le répertoire Drupal du site considéré puis :

drush generate-makefile /chemin/du/fichier-make.make

Et votre fichier .make sera automatiquement généré. Selon votre projet, des informations manquantes peuvent survenir, notamment si vous avez développé des modules custom. Éditez votre fichier .make en conséquence de façon à avoir une base propre de déploiement. 

Remarque : En utilisant generate-makefile, la version de chaque module sera précisé dans le fichier .make, de façon à avoir un Drupal à jour je vous conseille de supprimer les lignes précisant la version de vos modules.

Ainsi, avec Drush make, vous accélérerez considérablement votre mise en place de projets Drupal, en local ou sur vos serveurs.

 

Par AlanT
Alan Tondelier

Générer et personnaliser ses PDF avec Drupal et dompdf

Pour générer des fichiers PDF des pages Drupal, il existe le module "Print", qui contient le sous module "print_pdf". Ce module permet de convertir très simplement en PDF toute page possédant une URL interne. Print propose même un système de templates permettant de peaufiner l'affichage des PDF pour chaque type de nodes.

Cependant, il arrive d'avoir besoin de générer des PDF dont l'affichage diffère complètement de la page drupal associée et où des données non présentes sur la page doivent être récupérées. Cet article explique comment parvenir a ses fins en détournant un petit peu le module print. Cet article s'appuie sur la version 2.x du module.

Quelle librairie PDF choisir ?

Présentation

Lorsque vous installez le module print et que vous activez la génération de pdf (module print_pdf) il vous est demandé de déposer une librairie PDF dans votre Drupal. Il existe à ce jour 4 librairies PDF supportées par print pour générer vos PDF :

  1. dompdf
  2. TCPDF
  3. mPDF (avec la version 2.x de print)
  4. wkhtmltopdf

Chaque librairie possède ses avantages/inconvénients et leur choix va dépendre énormément de votre projet. Une étude comparative de ces 4 libraries est disponible sur fuseinteractive.ca . 

Personnellement, j'ai trouvé TCPDF trop "mauvais" dans la gestion des CSS. La mise en place de whtmltopdf délicate car on n'a pas toujours l'accès root du serveur qui héberge le site, même si c'est la solution la plus puissante (et la seule vraiment valable pour vos très gros pdf).

Concernant dompdf et mPDF, pour généraliser, dompdf a un meilleur support CSS que mPDF mais est moins performant que ce dernier.

J'ai eu l'occasion de pousser dompdf assez loin pour générer des pdf plutôt complexes : http://egrid.epg-project.eu/fr/egrid : 10 langues avec différents jeux de caractères, la possibilité d'ajouter un glossaire dans 4 langue de son choix, une numérotation des pages et un footer personnalisé.

Génération de PDF complexe avec Drupal
Extrat d'un PDF dynamique complexe avec Drupal avec footer personnalisé et numérotation de pages 

Pour la suite de cet article, j'utiliserai la bibliothèque dompdf pour générer mes fichiers.

Dompdf

Installer la librairie dompdf

Pour installer simplement la librairie dompdf, il vous faut :

  1. Récupérer la dernière version de dompdf : https://github.com/dompdf/dompdf/tags,
  2. Récupérer php-font-lib 0.2.2 : https://github.com/PhenX/php-font-lib/tree/0.2.2,
  3. Si vous ne l'avez pas, le module libraries,
  4. Dézipper dompdf dans sites/all/libraries/dompdf,
  5. Dézipper php-font-lib dans sites/all/libraries/dompdf/lib/php-font-lib,
  6. v2.0 du module : veillez à activer également le module "dompdf library handler".

Dompdf est installé, vous pouvez peaufiner vos réglages dans <admin>/config/user-interface/print .

Générer et personnaliser des PDF "sur-mesure" avec Dompdf

Ajouter des templates à n'importe quelle page possédant un lien interne

Le module print permet la personnalisation de templates selon le modèle hiérarchique suivant ( 1 sera prioritaire sur 2 qui sera prioritaire sur 3, etc...) : 

  1. print--[format]--node--[type]--[nid].tpl.php,
  2. print--[format]--node--[type].tpl.php,
  3. print--[format].tpl.php,
  4. print--node--[type].tpl.php,
  5. print.tpl.php dans votre thème,
  6. print.tpl.php dans le module print (par défaut).

[format] est le format de sortie du module print (html, pdf ou mail), [type] est le nom interne du type de contenu, [nid] est l'ID du node.

Cependant, cette structure ne permet pas d'appliquer un template à n'importe quelle page de notre site. Par exemple, comment faire pour ajouter un template PDF personnalisé pour une page générée par views ? Sans pour autant écraser le template général ?

Pour remédier à cela, vous pouvez utiliser hook_preprocess_print() :

template.php de votre theme

/**
 * Implements hook_preprocess_print().
 */

function demo_preprocess_print(&$vars){

  // add support for template files
  // print--[format]--path-[drupal-path].tpl.php
  // and
  // print--path-[drupal-path].tpl.php
  // with recursive path suggestions

  $cpath = current_path();
  $crumbs = explode('/',$cpath);

  // if first crumb is "print" remove it

  if($crumbs[0] == "print" ){ array_shift($crumbs); }

  $vars['theme_hook_suggestions'][] =  "print__path_${crumbs[0]}";
  $vars['theme_hook_suggestions'][] =  "print__${vars['format']}__path_${crumbs[0]}";

  // if there is more than one crumb
  if(count($crumbs) > 1){

    // remove crumb already used 
    array_shift($crumbs);

    foreach ($crumbs as $key => $crumb) {

      // get number of current theme suggestions
      $size = count($vars['theme_hook_suggestions']);

      // add crumb to theme suggestions
      $vars['theme_hook_suggestions'][] = $vars['theme_hook_suggestions'][$size-2]."_${crumbs[$key]}";
      $vars['theme_hook_suggestions'][] = $vars['theme_hook_suggestions'][$size-1]."_${crumbs[$key]}";

    }

  }

}

Ainsi, grâce a cette fonction, je peux facilement mettre en place un template pour personnaliser la sortie de mon pdf.

Si le chemin de ma vue est "mavue", le template PDF sera : print--pdf--path-mavue.tpl.php ou print--path-mavue.tpl.php (pour personnaliser à la fois le PDF et l'affichage pour impression).

Plus intéressant la fonction gère également les chemins à plusieurs arguments :
Par exemple si mon chemin est mavue/arg2, le template PDF pourra être (du plus selectif au moins selectif) :

  1. print--pdf--path-mavue-arg2.tpl.php,
  2. print--path-mavue-arg2.tpl.php,
  3. print--pdf--path-mavue.tpl.php,
  4. print--path-mavue.tpl.php

Ajouter un footer personnalisé à vos PDF et les numéros de pages...

Pour ajouter des informations en pied de page de vos PDF, vous devez tout d'abord activer l'utilisation de PHP dans dompdf. 
Rendez vous dans libraries/dompdf/dompdf_config.custom.inc.php et décommentez la ligne 12

define("DOMPDF_ENABLE_PHP", true);

Maintenant dans le template qui vous intéresse, rajoutez le code suivant après l'ouverture de la balise <body>

    <script type="text/php">
      if (isset($pdf)) {
        $font = Font_Metrics::get_font("verdana");;
        $size = 10;
        $color = array(0,0,0);
        $text_height = Font_Metrics::get_font_height($font, $size);

        $w = $pdf->get_width();
        $h = $pdf->get_height();

        $footer = $pdf->open_object();

        // Draw a line along the bottom
        $y = $h - 25;
        $pdf->line(15, $y, $w - 15, $y, $color, 1);

        $y += $text_height / 2;
        $pdf->page_text(15, $y, 'Texte de mon footer', $font, $size, $color);

        $pdf->close_object();
        $pdf->add_object($footer, "all");

        // Center the text
        $width = Font_Metrics::get_text_width("Page 1 of 2", $font, $size);
        $pagenumtxt = t("Page !n of !total", array("!n" => "{PAGE_NUM}", "!total" => "{PAGE_COUNT}"));
        $pdf->page_text($w - 15 - $width, $y, $pagenumtxt, $font, $size, $color);
      }
    </script>

Le code ci-dessous rajoutera une ligne, le texte "Texte de mon footer" et la numérotation des pages à droite. A vous d'adapter ce code pour coller à vos besoins. Pour plus d'options de mises en page, vous pouvez vous pencher sur l'API de dompdf .

J'espère que cet article vous fera gagner du temps lors de la mise en place de PDF avancés, il y aurait encore beaucoup de choses à dire sur le sujet, aussi si vous avez des remarques n'hésitez pas à les donner en commentaires !

Par Marc Delnatte
Akabia

Drupal vs Joomla - Quel CMS choisir pour son site internet ?

Choisir son CMS est important avant de commencer à développer son site internet. En effet, une fois choisi, il est très compliqué et coûteux de vouloir changer de CMS en cours de projet. Chaque CMS a sa propre architecture que ce soit Drupal ou Joomla.

Dans cet article nous allons comparer deux CMS (Joomla et Drupal) que l'agence Akabia a utilisé pour la réalisation de sites internet.







Par benftwc

Drupal Multisite et Travail collaboratif

Pourquoi le Multisite ?

Pour vous permettre de travailler en équipe sur un même projet, sans parler de CVS, Drupal a pensé au fichier sites.php, dédié aux « Multi-sites », soit, plusieurs sites au sein d’une seule instance de Drupal.

Drupal Multisite

Drupal Multisite

Le Drupal Multisite est généralement utilisé pour séparer plusieurs univers (tels que membre.site.fr et admin.site.fr), mais également plusieurs environnements techniques (Windows – Linux, Apache – NGinX).

Structure et mise en place du Drupal Multisite

Le mettre en place est extrêmement simple :

<?php
  $sites['subdomain.domain.tld'] = 'environnement';
?>

Pour reprendre la structure ci-dessus, la clé de $sites correspond à l’url et la valeur correspond au répertoire de configuration de l’environnement. (dans notre exemple, ROOT/sites/environnement).

Mise en place dynamique

Pour aller plus loin, et nous permettre de baser notre environnement en fonction du développeur, nous allons utiliser une variable d’environnement qui servira à séparer chaque base de donnée, pour chacun de vos développeurs / intervenants.

Cette variable est à renseigner dans le VHOST pointant vers votre instance Drupal

SetEnv APPLICATION_ENV dev-username

Avec ici autant d’utilisateurs que vous voudrez, en gardant 1 environnement / Vhost / URL !

Pensez également à versionner les config, cela évitera en cas de soucis de perdre toutes vos configurations !

<?php

// sites/sites.php
$env = getenv('APPLICATION_ENV');
if (!empty($env)) {
    $sites[$_SERVER['SERVER_NAME']] = $env;
}
?>

En sauvegardant ce code dans votre sites.php, vous serez capable de travailler à plusieurs développeurs sur une même instance de Drupal. Pensez également à synchroniser de temps en temps vos bases de données si nécessaire, cette technique n’est pas « viable » lorsque vous travaillerez avec trop de personnes.

Aller plus loin

Dans ce cas, il faudra prévoir de passer par des méthodes plus « Drupal », soit, par le biais de hook_update, d’export Features-Strongarm, ou de modules Custom ne nécessitant que très peu de configuration.

The post Drupal Multisite et Travail collaboratif appeared first on Benftwc.

Par benftwc

Drupal et le Responsive Design

Drupal responsive design

Drupal responsive design

Avant tout, sur Drupal, le Responsive Web Design, c’est quoi / pour qui ?

Avec le nouvel essors des plateformes mobiles et la naissance des webapps, il est aujourd’hui devenu primordial à toute société de posséder son propre site « responsive webdesign » (que j’abrégerais RWD), c’est à dire, un site adaptatif, calculé et affiché différemment en fonction du support (mobile, tablette, ordinateur, téléviseurs). Cependant, si cette fonctionnalité n’est pas pensée au début, il peut vite devenir fastidieux de le mettre en place.

Je distingue 2 grandes réponses au « problème » du RWD : La mise en place d’un template « full RWD » et la mise en place d’un thème dedié.

Template Full RWD

Cette solution est la plus simple car tout se passe au niveu de votre intégration, soit, HTML + CSS + JavaSript. Cette solution ne touchant pas à Drupal, et étant traité par Marie Guillaumet (Refonte de mon portfolio partie 1 et partie 2), je n’en parlerais pas plus ici.

Le thème dedié

Le thème dedié est plus pratique dans certains cas, notament quand le site est déjà sorti, avec toute une intégration de prévue et pas de temps pour le refaire. Néanmoins, cela impliquera autant de modifications et de temps de maintient que de thèmes dédiés.

La technique est simple ici, il vous suffit d’utiliser le module Mobile Tools vous allez pouvoir détecter quel est le support du visiteur, et lui fournir un thème différent en fonction du retour.

De cette manière, vous aurez par exemple desktop_mondesign et mobile_mondesign, les deux adaptés au contenu (soit PC pour desktop, smartphone/iphone pour mobile).

De plus, le module embarque des options de configuration pour CCK, Display Suite, Panels … En soit, la méthode est plus compliquée à mettre en place, mais permet une réelle séparation des fichiers, ce qui n’est pas le cas de la première  méthode.

The post Drupal et le Responsive Design appeared first on Benftwc.

Par AlanT
Alan Tondelier

Les formulaires multi-étapes en ajax avec le module mforms

Les fomulaires multi-étapes permettent de récupérer de nombreuses informations sur l'utilisateur sans l'assomer d'un coup avec une grande quantité d'informations. Pour les besoins d'un projet, je me suis penché sur la réalisation d'un formulaire multi-étapes (ou multi-steps en anglais) sous Drupal.

Je recherchais une solution permettant d'afficher une barre de progression, un nombre variables d'étapes, un comportement en ajax, et la possibilité d'accéder facilement aux données utilisateur saisies. Des solutions envisagées j'ai retenu le module mforms. Le résultat de son implémentation est visible ici.

Retour sur expérience.

Un module complet

Installation & exemple

On commence par récupérer le module.

drush dl mforms -y

Une fois téléchargé, le module mforms est livré avec un module d'exemple complet que je vous recommande d'activer.

drush en mforms,mforms_example -y

Au moment de l'écriture de cet article, il existe un bug dans le module d'exemple concernant la gestion de plusieurs formulaires mforms sur la même page. Si vous rencontrez le soucis, utilisez le module developpement.

Un module, deux approches

Si vous avez activé le module d'exemple, vous pouvez vous rendre sur la page <votredrupal>/mforms pour une page d'exemple de mise en place de votre module.

Le module mforms propose deux façons pour gérer le contenu de vos formulaires multi-étapes :

  1. Un stockage dans la variable $form_state ( variable Drupal de stockage des champs de formulaires )
  2. Un stockage des données dans une varriable de SESSION.

Ces deux approches diffèrent principalement au niveau de la persistance des variables.
En effet les variables stockées avec $form_state seront rafraichies au chargement de la page, l'utilisation de $form_state est à privilégier pour les formulaires multi-étapes "simple" ou la deuxième étapes du fomulaire est une étape de validation de données (par exemple).

À contrario, l'utilisation d'une variable de SESSION va permettre de réutiliser les données saisies par l'utilisateur sur l'ensemble du site Internet mais également de revenir sur les saisies effectuées. C'est cette approche que j'ai retenu pour mon projet.

Construction d'un formulaire multi-étapes

Notre formulaire multi-étapes va faire l'objet d'un module personnalisé. Pour cet exemple je vais appeler le module multi_etapes. Comme nous allons traiter de la réalisation d'un module Drupal, le code sera commenté en anglais pour être en accord avec les bonnes pratiques Drupal. Si certains bouts de codes ne sont pas clairs, n'hésitez pas à poser vos questions en commentaire.

Les bases du module

Je ne reviens pas sur les bases d'un module Drupal, tout est bien expliqué sur la documentation officielle.

multi_etapes.info 

name = Multi Etapes
description = Add a multi-steps session based form. Built with the mforms module.
core = 7.x

; Package name 
package = Alan

; Module dependencies
dependencies[] = mforms

Ensuite le fichier .module :

multi_etapes.module

<?php

/**
 * @file
 * Add a multi-steps session based form. Built with the mforms module.
 */

/**
 * Implements hook_permission().
 */
function multi_etapes_permission() {
  return array(
    // 'administer my module' =>  array(
    // 'title' => t('Administer my module'),
    // 'description' => t('Perform administration tasks for my module.'),
    // ),
    'access multi-steps forms' => array(
      'title' => t('Access multi-steps forms'),
      'description' => t('Enable the user to fill-in custom multi-steps forms'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function multi_etapes_menu() {

  $items['myform'] = array(
    'title' => t('My multi-steps form'),
    'page callback' => 'multi_etapes_myform_page',
    'access arguments' => array('access multi-steps forms'),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'inc/multi_etapes.pages.inc',
  );

  return $items;
}

/**
 * Implements hook_STORE_KEY_mforms_init().
 */
function multi_etapes_myform_mforms_init() {
  $store = MformsSessionStore::getInstance('myform');
  $steps = MformsSteps::getInstance($store);

  // If using mustistep controls you need to explicitly define form steps and
  // its attributes.
  $controls = MformsMultiStepControls::getInstance($store, $steps, array(
    '_myform_step1' => array('value' => t('Bio'), 'weight' => -103),
    '_myform_step2' => array('value' => t('Hobbies'), 'weight' => -102),
    '_myform_step3' => array('value' => t('Summary'), 'weight' => -101)
  ));
  // Ajaxify the form stepping process.
  $controls->ajaxify();

  // Init the mforms.
  mforms_init_module('multi_etapes', 'myform', $store, $controls);
}

Qu'avons-nous fait ?

  1. On créé un droit pour accéder au formulaire multi-étape,
  2. On défini une entrée de menu "classique" pour accéder à ce formulaire (protégée par le droit créé précédemment),
  3. On indique que la fonction de callback "multi_etapes_myform_page" se situe dans le fichier /inc/ du module,
  4. On initialise notre formulaire multi-étapes où myform est la clef via le hook hook_STORE_KEY_mforms_init(),
  5. On défini le nombre d'étapes à l'intérieur du hook et on leur donne un nom (attention au poids),
  6. On fini d'initialiser le formulaire.

inc/multi_etapes.pages.inc

<?php

/**
 * Entry page for the multi-step form.
 *
 * @return array
 *   Drupal renderable array.
 */
function multi_etapes_myform_page() {

  // Add user name to steps
  global $user;
  $uname = isset($user->name)?$user->name:'Guest';
  
  // Create parameters to be passed to the multi-step form
  $params = array('uname' => $uname);

  // Return Drupal renderable array.
  return array(
    'mform' => drupal_get_form('multi_etapes_myform', $params),
  );
}

/**
 * Callback function to generate form.
 *
 * @param array $form
 *   Drupal form array.
 * @param array $form_state
 *   Drupal form_state array.
 * @param array $params
 *   Optional params passed into form.
 *
 * @return array
 *   Drupal form array.
 */
function multi_etapes_myform($form, &$form_state, $params) {
  // pass defined parameters to mforms_build
  return mforms_build('myform', '_myform_step1', $form_state, $params);
}

/**
 * Callback function to validate form inputs
 *
 * @param array $form
 *   Drupal form array.
 * @param array $form_state
 *   Drupal form_state array.
 */
function multi_etapes_myform_validate($form, &$form_state) {
  mforms_validate('myform', $form, $form_state);
}

/**
 * Callback function to process the form inputs.
 *
 * @param array $form
 *   Drupal form array.
 * @param array $form_state
 *   Drupal form_state array.
 */
function multi_etapes_myform_submit($form, &$form_state) {
  mforms_submit('myform', $form, $form_state);
}

Encore beaucoup d'initialisations dans ce fichier :

  1. On défini la fonction appelée par notre menu,
  2. On récupère le nom de l'utilisateur courant pour montrer le passage de variable à notre formulaire,
  3. On appelle le formulaire via drupal_get_form,
  4. Notre formulaire multi-étapes est défini de façon traditionnelle avec les hook_form , hook_validate et hook_submit.

Il nous reste à mettre en place le code structurant chacune des étapes de notre formulaire.
Le module mform va chercher les étapes ( définies par _myform_stepX() ) dans un fichier qui doit être nommé de la façon suivante : nom_du_module.cleformulaire.inc et placé dans un dossier mforms à la racine de votre module.

Le coeur du fomulaire multi-étapes

Nous allons faire un formulaire d'exemple en 3 étapes :

  1. Informations sur l'utilisateur avec son login récupéré automatiquement, 
  2. Ses activités (Films, livres et sports),
  3. Un résumé des valeurs saisies, un champ pour envoyer un message à l'équipe du site et une case a cocher pour valider et terminer le formulaire.

Ce formulaire reprend les éléments du formulaire d'exemple fourni par le module mforms, en ajoutant des variations qui me semblent intéressantes.

mforms/multi_etapes.myform.inc - Première étape

/**
 * First step called by the Mforms state machine.
 *
 * @param array $form_state
 *   Drupal form_state array.
 * @param string $next_step
 *   Mforms next step callback name.
 * @param mixed $params
 *   Optional params passed into form.
 *
 * @return array
 *   Drupal form array.
 */
function _myform_step1(&$form_state, &$next_step, $params) {
  // Define following step callback. If none set, that implies it is
  // the last step.
  $next_step = '_myform_step2';

  // Retrieve submitted values. This comes in handy when back action
  // occured and we need to display values that were originaly submitted.
  $data = mforms_get_vals('myform');

  // If we have the data it means we arrived here from back action, so show
  // them in form as default vals.
  if (!empty($data)) {
    $vals = $data;
  }
  elseif (isset($form_state['values'])) {
    $vals = $form_state['values'];
  }

  // Define form array and return it.
  $form = array();

  $form['login'] = array(
    '#type' => 'textfield',
    '#disabled'=>true,
    '#title' => t('Login'),
    '#default_value' => isset($vals['loginv']) ? $vals['loginv'] : $params['uname'], // get login name from previous page (not submited but for design purpose).
  );

  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
    '#default_value' => isset($vals['name']) ? $vals['name'] : NULL,
  );
  $form['email'] = array(
    '#type' => 'textfield',
    '#title' => t('Email'),
    '#default_value' => isset($vals['email']) ? $vals['email'] : NULL,
    '#required' => TRUE,
  );
  $form['www'] = array(
    '#type' => 'textfield',
    '#title' => t('Your web site'),
    '#default_value' => isset($vals['www']) ? $vals['www'] : NULL,
  );

  // store the login in a hidden field so that the value is submited

  $form['loginv'] = array(
    '#type' => 'hidden',
    '#default_value' => isset($vals['loginv']) ? $vals['loginv'] : $params['uname'],
  );

  return $form;
}

/**
 * Validate callback - validates email address.
 *
 * @param array $form
 *   Drupal form array.
 * @param array $form_state
 *   Drupal form_state array.
 */
function _myform_step1_validate($form, &$form_state) {
  if (!valid_email_address($form_state['values']['email'])) {
    form_set_error('email', t('Invalid email.'));
  }
}
  1. On défini la fonction de première étape,
  2. On indique l'étape suivante,
  3. On défini les champs à afficher tout en peuplant les valeurs présaisies si elles existent,
    Pour cet exemple, le champ "Login" est récupéré automatiquement. Si l'utilisateur est anonyme, "Guest" est affiché,
  4. On soumet la première étape du fomulaire à la fonction de validation.

mforms/multi_etapes.myform.inc - Deuxième étape

/**
 * Step two.
 *
 * @param array $form_state
 *   Drupal form_state array.
 * @param string $next_step
 *   Mforms next step callback name.
 * @param mixed $params
 *   Optional params passed into form.
 *
 * @return array
 *   Drupal form array.
 */
function _myform_step2(&$form_state, &$next_step, $params) {
  $next_step = '_myform_step3';
  $form = array();

  $data = mforms_get_vals('myform');

  if (!empty($data)) {
    $vals = $data;
  }
  elseif (isset($form_state['values'])) {
    $vals = $form_state['values'];
  }

  $form['movies'] = array(
    '#type' => 'textarea',
    '#title' => t('Movies'),
    '#default_value' => isset($vals['movies']) ? $vals['movies'] : NULL,
  );
  $form['books'] = array(
    '#type' => 'textarea',
    '#title' => t('Books'),
    '#default_value' => isset($vals['books']) ? $vals['books'] : NULL,
  );
  $form['sports'] = array(
    '#type' => 'textarea',
    '#title' => t('Sports'),
    '#default_value' => isset($vals['sports']) ? $vals['sports'] : NULL,
  );

  return $form;
}

Rien de plus par rapport à l'étape 1, on passe à la dernière étape de ce formulaire.

mforms/multi_etapes.myform.inc - Troisième étape

/**
 * Third step.
 *
 * @param array $form_state
 *   Drupal form_state array.
 * @param string $next_step
 *   Mforms next step callback name.
 * @param mixed $params
 *   Optional params passed into form.
 *
 * @return array
 *   Drupal form array.
 */
function _myform_step3(&$form_state, &$next_step, $params) {
  $form = array();

  // Get the collected values submited at each step.
  // Here is one difference - the second parameter that defines the step
  // from which we want to retrieve the data.
  $vals1 = mforms_get_vals('myform', '_myform_step1');
  $vals2 = mforms_get_vals('myform', '_myform_step2');

  $form['summary'] = array(
    '#type' => 'fieldset',
    '#title' => t('Summary'),
  );

  $form['summary']['sum_bio'] = array(
    '#markup'=>
    "<h3>".t('Bio')."</h3>
    <ul>
      <li><em>".t('Login')." :</em> ${vals1['loginv']}</li>
      <li><em>".t('Name')." :</em> ${vals1['name']}</li>
      <li><em>".t('e-mail')." :</em> ${vals1['email']}</li>
      <li><em>".t('Website')." :</em> ${vals1['www']}</li>
     </ul>",
  );

  $form['summary']['sum_hobbies'] = array(
    '#markup'=>
    "<h3>".t('Hobbies')."</h3>
    <ul>
      <li><em>".t('Movies')." :</em> ${vals2['movies']}</li>
      <li><em>".t('Books')." :</em> ${vals2['books']}</li>
      <li><em>".t('Sports')." :</em> ${vals2['sports']}</li>
     </ul>",
  );



  $data = mforms_get_vals('myform');

  if (!empty($data)) {
    $vals = $data;
  }
  elseif (isset($form_state['values'])) {
    $vals = $form_state['values'];
  }

  $form['message_team'] = array(
    '#type' => 'textarea',
    '#title' => t('A message for the team'),
    '#default_value' => isset($vals['message_team']) ? $vals['message_team'] : NULL,
  );

  $form['confirm']=array(
    '#type' => 'checkbox',
    '#title' => t('Validate and end the survey'),
  );

  return $form;
}

/**
 * Validate callback.
 *
 * @param array $form
 *   Drupal form array.
 * @param array $form_state
 *   Drupal form_state array.
 */
function _myform_step3_validate($form, &$form_state) {
  if (!$form_state['values']['confirm']) {
    form_set_error('confirm', t('You have to validate the survey in order to continue !'));
  }
}

/**
 * Implement submit callback for the last step to process all data submitted.
 *
 * @param array $form
 *   Drupal form array.
 * @param array $form_state
 *   Drupal form_state array.
 */
function _myform_step3_submit($form, &$form_state) {
  // Here do what you want with the data

   multi_etapes_save_data() // exemple function

  // Send a mail to the team if there is a custom message

  if($form_state['values']['message_team'] && !empty($form_state['values']['message_team'])){
    // add your own mail function
    if(!_multi_etapes_drupal_mail('contact@votresite.com','webmaster@votresite.com',t('Answer to the survey'),$form_state['values']['message_team'])){

      drupal_set_message(t('Something went wrong'),'error');

    }

  }

  // Call mforms_clean(); 
  // Clear all data from the session variable

  mforms_clean('myform');

  drupal_set_message(t('Thank you for your time.'));
}
  1. Cette fois on affiche un résumé des information saisies précédemment, on utilise la fonction mforms_get_vals avec un second paramètre pour récupérer les valeurs d'une étape en particulier,
  2. On affiche les résultats des deux étapes précédentes,
  3. On affiche un champ pour que l'utilisateur puisse envoyer un message à l'équipe du site,
  4. On met en place une case à cocher pour valider nos résultats et envoyer le message (si saisi),
  5. Une fonction de validation vérifie que la case a bien été cochée lors de l'envoi du formulaire,
  6. La fonction d'envoi traite les données (je ne développe pas ce point, mais on peut imaginer que les données saisies viennent peupler une node ou une entitée personnalisée),
  7. Si l'utilisateur a entré un message à destination de l'équipe on envoi ce message par mail (par exemple),
  8. On vide le contenu de notre formulaire (effacement de la variable de SESSION) et on affiche un message à l'utilisateur.

Et voilà ! Notre module est en place et fonctionnel. Les possibilités sont nombreuses et le système robuste permet de créer n'importe quel type de formulaire multi-étape.

Pour aller plus loin

Quelques astuces complémentaires.

Execution de javascript

Lors de la réalisation du formulaire multi-étape pour le site applicatif de l'eGrid, j'ai eu besoin d'executer du code javascript pour réaliser un carrousel (étape Évaluation).

Le problème avec l'execution de javascript dans les appels en ajax Drupal, c'est qu'il est toujours délicat de savoir à quel moment se "brancher" pour executer son code. Le morceau de javascript suivant permet d'executer le code souhaité à l'étape désirée. Attention cependant le code est réinterprété a chaque reconstruction du DOM (et donc à chaque affichage de message d'erreur de validation).

J'ai placé le code dans js/multi_etapes.js et modifié multi_etapes.info pour déclarer le fichier js ( scripts[] = js/multi_etapes.js ).

(function ($, Drupal, window, document, undefined) {

  Drupal.behaviors.multi_etapes = {
    attach: function(context, settings) {

      if(context === document || context[0].nodeName == 'FORM'){
          var step = $('[id^="edit-steps-btns-wrapper"] .current-step').attr('id');

          var regex = /step(\d)/;
          var match = regex.exec(step);
          step = parseInt(match[1]);

          alert('Etape ' + step);
          // on peut envisager un switch pour gérer chaque étape.
      }
    }
  }
})(jQuery, Drupal, this, this.document);

Si vous vous aventurez dans la réalisation d'un tel formulaire avec javascript, je serai très interessé par vos retours et vos solutions pour bien gérer l'execution JS.

Accéder aux données de la session

Le fait de travailler avec les sessions permet d'accéder à tout moment aux valeurs du formulaire. Ceci m'a été particulièrement utile lors de la génération d'une fiche de résumé des saisies en PDF. Pour accéder aux valeurs stockées :

$valeurs = $_SESSION['clefduformulaire']

Ce sera tout pour aujourd'hui concernant les formulaires multi-étapes sous Drupal, il existe d'autres méthodes utilisant le module webform ou en construisant directement avec l'API form de Drupal, avez-vous essayé ces autres méthodes ? Qu'en pensez-vous ?

Par AlanT
Alan Tondelier

Installer et personnaliser le module CKEditor pour Drupal 7

Installer et personnaliser le module CKEditor pour Drupal 7

La mise en place du module ckeditor pour Drupal peut s'avérer plus compliquée que prévue. Ce rapide guide liste les étapes à suivre pour installer sans encombres le module. Une seconde partie s'intéresse à l'installation de plugins complémentaire étendant les fonctionnalités de cet éditeur wysiwyg de qualité.

Ajouter ckeditor à votre Drupal

Récupération des fichiers

Tout commence par une petite commande drush bien sentie. Si vous ne connaissez pas drush, faites vrombir votre curseur au plus vite pour le récupérer, cet utilitaire en ligne de commandes est un indispensable du développement Drupal (j'y reviendrai). Attention les commandes ci-dessous ne fonctionnent qu'avec les dernières versions de drush, pour les plus anciennes vous devez d'abord télécharger le module (avec le switch "dl").

drush en ckeditor -y

Je vous conseille également de récupérer ckeditor_link qui vous permettra de créér des hyperliens vers vos contenus Drupal directement via l'interface de Ckeditor, indispensable !

drush en ckeditor_link -y

Une fois la récupération des modules faite, rendez vous sur http://ckeditor.com/download pour télécharger la librairie ckeditor.

Une petite personnalisation SEO-friendly

Afin de fournir du code plus moderne, apprécié des moteurs de recherches mais également pour fournir plus d'accessibilité à vos contenus, j'ai l'habitude d'effectuer une petite personnalisation de ckeditor avant de le télécharger : ajouter le support de la balise <figure> et <figcaption>.

Sur la page de ckeditor, prenez l'option "Or let met customize CKEditor" puis le bouton rouge.
Prendez le preset "Full" puis dans la partie basse, colonne de droite trouvez "Enhanced Image" et basculez-le colonne de gauche.

Si vous suivez cette étape, les  images que vous chargerez via CKEditor pourront être enrichies de la sémantique HTML5.


Le plugin Enhanced Image ajoutera les balises html5 figure et figcaption.

Ajoutez ensuite toutes les langues à ckeditor (j'ai rencontré des problèmes en ne choisissant que les langues utilisées sur mes sites), et récupérez votre librairie.

Une fois votre CKEditor téléchargé, placez le contenu de l'archive dans votre dossier /sites/all/modules/contrib/ckeditor/ckeditor .

CKFinder pour gérer vos fichiers

CKEditor ne sait gérer seul l'upload de fichiers sur votre serveur, pourtant il est très utile de pouvoir ajouter des visuels ou attacher des fichiers directement dans le corps de votre texte.
Heureusement, il existe des plugins pour remédier à ce manque. 

Le plus connu et utilisé d'entre eux se nomme CKFinder (payant mais possède une version de démonstration avec quelques limitations pour un usage non commercial).

Pour l'ajouter à votre CKEditor, les étapes sont les suivantes :

  1. Récupérez le plugin ici,
  2. Drupal cherchera par défaut ckfinder dans le répertoire /sites/all/modules/contrib/ckeditor/ckfinder. Dézippez-le à cet emplacement.
  3. Pour que le système de droits de Drupal gère correctement les permissions de ckeditor, vous devez modifier le fichier config.php de CKFinder.

Supprimez ces lignes (21-34) :

function CheckAuthentication()
{
    // WARNING : DO NOT simply return "true". By doing so, you are allowing
    // "anyone" to upload and list the files in your server. You must implement
    // some kind of session validation here. Even something very simple as...

    // return isset($_SESSION['IsAuthorized']) && $_SESSION['IsAuthorized'];

    // ... where $_SESSION['IsAuthorized'] is set to "true" as soon as the
    // user logs in your system. To be able to use session variables don't
    // forget to add session_start() at the top of this file.

    return false;
}

Et remplacez les par 

require_once '../../../../includes/filemanager.config.php';
  1. Finissez par éditer la variable $cookie_domain de votre settings.php
 $cookie_domain = '.votrenomdedomain.ext';

Votre CKFinder est maintenant fonctionnel.

Configuration de CKEditor

Les bases

Par défaut CKEditor a créé deux profils à partir des formats de textes installés par défaut (lors d'une mise en route standard de Drupal). Nous allons voir brievement la configuration d'un de ces profils.

La configuration des profils se fait dans admin/config/content/ckeditor/.

Modifiez l'un des profil qui vous intéresse et dans "Apparence de l'éditeur", choisissez les boutons de barre d'outil à faire apparaitre pour ce profil. Si vous souhaitez de plus activer le CKEditor Link, cochez la case dans la sous rubrique Plugins ET rendez vous dans la configuration du format de texte correspondant pour activer le filtre CKEditor Link afin d'avoir de belles URLs.

Je vous conseille également de limiter les balises dans "Nettoyer et afficher" > "Formats de polices de caractères". Bien souvent la balise H1 est inutile car déjà présente pour le titre de la page, d'autres balises peuvent selon vos cas être inutiles ou source de confusion pour les utilisateurs, à vous de faire le tri.

N'oubliez pas non plus d'activer CKFinder dans les "paramètres de l'explorateur de fichiers".

Une fois ces réglages effectués, CKEditor devrait être visible dans vos zones de textes possédant un format de texte associé à un profil.

Configurations avancées

Très vite, il devient intéressant de pouvoir définir ses propres styles dans ckeditor. Pour ce faire, dans les réglages d'un profil, dans CSS puis styles prédéfinis, définissez le chemin de ckeditor.styles.js, j'ai l'habitude d'utiliser cette syntaxte "%tjs/ckeditor.styles.js" pour appeler le fichier dans le theme principal du site (et non celui de l'administration comme le suggère Drupal !).

L'appel dans le thème évite de supprimer le fichier lors d'une mise à jour du module ou de la librairie.

Vous trouverez la copie originale de ckeditor.style.js dans le répertoire du module CKEditor. Voici un extrait du ckeditor.styles.js que j'utilise sur ce blog :

/*
Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/

/*
 * This file is used/requested by the 'Styles' button.
 * The 'Styles' button is not enabled by default in DrupalFull and DrupalFiltered toolbars.
 */
if(typeof(CKEDITOR) !== 'undefined') {
    CKEDITOR.addStylesSet( 'drupal',
    [

            /* Block Styles */

            // code wrapper

            {

                name: 'Code Wrapper',
                element: 'pre',

            },

            /* Inline Styles */

            // These are core styles available as toolbar buttons. You may opt enabling
            // some of them in the "Styles" drop-down list, removing them from the toolbar.

            { name : 'Bleu'  , element : 'span', attributes : { 'class' : 'bleu' } },
            { name : 'Orange'  , element : 'span', attributes : { 'class' : 'orange' } },

            { name : 'Big'        , element : 'big' },
            { name : 'Small'      , element : 'small' },

            // code

            {
                    name : 'Code PHP',
                    element : 'code',
                    attributes :
                    {
                            'class' : 'language-php',
                    }
            },

            {
                    name : 'Code CSS',
                    element : 'code',
                    attributes :
                    {
                            'class' : 'language-css',
                    }
            },

            {
                    name : 'Code HTML',
                    element : 'code',
                    attributes :
                    {
                            'class' : 'language-markup',
                    }
            },

            {
                    name : 'Code JS',
                    element : 'code',
                    attributes :
                    {
                            'class' : 'language-javascript',
                    }
            },

...etc

Étendre CKEditor

Ajout de plugins

La communauté de CKEditor a créé un certain nombre de plugins téléchargeables sur cette page : http://ckeditor.com/addons/plugins/all.

Ces plugins s'incorporent directement au ckeditor de votre Drupal en téléchargeant l'archive du plugin, et en l'extrayant deux fois, dans le dossier /modules/contrib/ckeditor/plugins et dans /modules/contrib/ckeditor/ckeditor/plugins. (En réalité il n'est pas nécessaire de tout extraire en double, mais sachez que cette méthode est "sûre").

Une fois vos plugins ajoutés, leur activation se fait dans "Apparence de l'éditeur" > "Plugins".

Création de plugin

Il est évidemment possible de créer son propre plugin CKEditor au sein même de Drupal, je reviendrai sur ce point lors d'un prochain billet.

 

Pages