Chapitre 4 Design adaptif (responsive) avec Dynacase Document UIs

Nous avons vu dans le chapitre précédent que le document est responsive par défaut : en dessous de 480px, les libellés passent au dessus des attributs. Nous allons voir dans ce chapitre comment aller plus loin.

4.1 Principe

Nous allons injecter une CSS qui change la mise en forme du document, afin de le rendre responsive. L'objet de ce chapitre n'est pas d'expliquer la CSS, mais de montrer comment on peut

  • adresser les éléments générés
  • surcharger un template pour ajouter d'autres éléments adressables en css

Voici à quoi ressemblera le document final :

Fiche de contact

Figure 4. Fiche de contact

4.2 Mise en œuvre du design responsive

4.2.1 Mise en place du contrôle de rendu

Nous allons créer un contrôle de rendu afin de surcharger le rendu du document. Pour rappel, le contrôle de rendu se manipule de la même manière que le contrôle de vue :

  • il est créé
  • il est ensuite attaché à la famille
    • soit au moyen du cycle de vie
    • soit directement sur la famille

4.2.1.1 Récupération des sources

Les sources avant cette étape correspondent au tag step-30-00.

4.2.1.2 Paramétrage

Le contrôle de rendu fera référence à une classe de rendu. Cette classe de configuration rendu doit être initialisée avant création du contrôle de rendu. Elle sera utilisée pour modifier le rendu du document dans les étapes suivantes.

Voici le contenu du fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/ContactRenderConfigView.php :

<?php
 
namespace DduiTuto;
 
class ContactRenderConfigView extends \Dcp\Ui\DefaultView
{
 
}

Une fois cette classe déployée, le contrôle de rendu peut être créé à cette adresse : http://localhost:8080/?app=GENERIC&action=GENERIC_EDIT&classid=CVRENDER

Nous allons le compléter avec les informations suivantes :

  • Titre : Contact (Contrôle de rendu)
  • Famille : Contact
  • Vues : une seule vue, avec les éléments suivants
    • Identifiant de la vue : DEFAULT_VIEW
    • Label : Consultation
    • Type : Consultation
    • Classe de configuration de rendu : \DduiTuto\ContactRenderConfigView
    • Masque : vide
    • Ordre de sélection : 10
    • Affichable : Non
    • Menu : vide
Contrôle de rendu

Figure 5. Contrôle de rendu

Une fois ajouté dans le workflow de la famille Contact pour chacun des états, exporté, et correctement ajouté au fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/DDUI_TUTO_CONTACT__DATA.csv, il peut être déployé.

4.2.1.3 Déploiement

Les sources telles que déployées à cette étape correspondent au tag step-30-10

Le déploiement se fait au moyen du developer toolkit (pour plus d'explications sur les outils de développement, se rendre sur leur documentation) :

  • pour linux :

    php dynacase-devtool.phar deploy -u localhost -p 8080 -c dynacase -s path/to/sources --auto-release
  • pour windows :

    dynacase-devtool.bat deploy -u localhost -p 8080 -c dynacase -s path/to/sources --auto-release

Puisque le contrôle de rendu a été associé au cycle de vie après la création du document que nous manipulons, il n'est pas associé automatiquement. Il faudrait soit écrire un script de migration, soit créer un nouveau document. Pour plus de simplicité, nous avons intégré une méthode à notre document pour refaire l'association.

il suffit de se connecter à l'adresse http://localhost:8080/?app=FDL&action=FDL_METHOD&id=CONTACT_JOHN_DOE&method=updateCR

4.2.1.4 Le résultat

En consultant le contact John DOE à l'adresse http://localhost:8080/api/v1/documents/CONTACT_JOHN_DOE.html, aucun changement n'est perceptible. En effet, nous avons juste mis en place les points d'entrée pour nos personnalisation à venir.

4.2.2 CSS uniquement

Nous allons dans cette partie voir comment surcharger le rendu uniquement par CSS.

L'objectif est de

  • Quelle que soit la résolution :
    • Retirer le libellé de la photo
  • En dessous de 1024px :
    • Retirer le libellé du logo
  • à partir de 480px :
    • positionner la photo à gauche du cadre "Identité",
    • conserver le positionnement des autres éléments du cadre "Identité"
  • entre 480px et 1024px :
    • Retirer le libellé du logo
    • positionner la photo à gauche du cadre "Identité",
    • conserver le positionnement des autres éléments du cadre "Identité"
  • à partir de 1024px :
    • positionner les cadres "Société" et "Coordonnées professionnelles" côte à côte
  • à partir de 1280px :
    • Retirer le libellé du logo
    • positionner le logo à gauche du cadre "Société",
    • conserver le positionnement des autres éléments du cadre "Société"

Soit, en images :

Résolution inférieure à 480px

Figure 6. Résolution inférieure à 480px

Résolution entre 480px et 1024px

Figure 7. Résolution entre 480px et 1024px

Résolution entre 1024px et 1280px

Figure 8. Résolution entre 1024px et 1280px

Résolution supérieure à 1280px

Figure 9. Résolution supérieure à 1280px

4.2.2.1 Récupération des sources

Les sources avant cette étape correspondent au tag step-30-10.

4.2.2.2 Code

Nous devons en premier lieu injecter la nouvelle CSS dans le document en plus des CSS qu'il utilise déjà. Pour ce faire, ajoutons une méthode getCssReferences à notre classe de configuration de rendu dans le fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/ContactRenderConfigView.php :

public function getCssReferences(\Doc $document = null)
{
    $version = \ApplicationParameterManager::getParameterValue(
        "CORE", "WVERSION"
    );
 
    $cssReferences = parent::getCssReferences($document);
 
    $cssReferences['DDUI_TUTO_CONTACT_view']
        = "DDUI_TUTO/Families/DDUI_TUTO_CONTACT/Layout/view.css?ws="
        . $version;
 
    return $cssReferences;
}

Nous pouvons maintenant écrire la CSS correspondante dans le fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/Layout/view.css :

/******************************************************************************
 cadre identité
******************************************************************************/
 
/* masquage du label de la photo */
label[data-attrid="dc_photo"] {
    display: none;
}
 
@media (min-width: 480px) {
 
    /* Positionnement de la photo à gauche */
    .dcpAttribute[data-attrid="dc_photo"] {
        float: left;
        width: 66px;
    }
 
    .dcpAttribute__content[data-attrid="dc_photo"] {
        padding: 0;
    }
 
    /* Restauration de la position initiale de tous les attributs autres que la photo */
    .dcpFrame__content[data-attrid=dc_fr_ident] .dcpAttribute:not([data-attrid="dc_photo"]) {
        float: right;
        width: calc(100% - 66px);
    }
 
    .dcpFrame__content[data-attrid=dc_fr_ident] label:not([data-attrid="dc_photo"]) {
        width: calc((100% / 3) - 44px);
    }
}
 
/******************************************************************************
 cadre Société
******************************************************************************/
 
@media (max-width: 1024px),
       (min-width: 1280px) {
 
    /* masquage du label du logo */
    label[data-attrid="dc_logo"] {
        display: none;
    }
}
 
@media (min-width:480px) and (max-width:1024px),
       (min-width: 1280px) {
 
    /* Positionnement du logo à gauche */
    .dcpAttribute[data-attrid="dc_logo"] {
        float: left;
        width: 66px;
    }
 
    .dcpAttribute__content[data-attrid="dc_logo"] {
        padding: 0;
    }
 
    /* Restauration de la position initiale de tous les attributs autres que le logo */
    .dcpFrame__content[data-attrid=dc_fr_society] .dcpAttribute:not([data-attrid="dc_logo"]) {
        float: right;
        width: calc(100% - 66px);
    }
 
    .dcpFrame__content[data-attrid=dc_fr_society] label:not([data-attrid="dc_logo"]) {
        width: calc((100% / 3) - 44px);
    }
}
 
/******************************************************************************
 Positionnement côte à côte des cadres "Société" et "Coordonnées professionnelles"
******************************************************************************/
@media (min-width: 1024px) {
    .dcpFrame[data-attrid=dc_fr_society],
    .dcpFrame[data-attrid=dc_fr_coord] {
        float: right;
        width: calc(50% - 10px);
    }
 
    .dcpFrame[data-attrid=dc_fr_society] {
        float: left;
    }
 
    .dcpFrame[data-attrid=dc_fr_coord] {
        float: right;
    }
}

4.2.2.3 Déploiement

Les sources telles que déployées à cette étape correspondent au tag step-30-20

Le déploiement se fait au moyen du developer toolkit (pour plus d'explications sur les outils de développement, se rendre sur leur documentation) :

  • pour linux :

    php dynacase-devtool.phar deploy -u localhost -p 8080 -c dynacase -s path/to/sources --auto-release
  • pour windows :

    dynacase-devtool.bat deploy -u localhost -p 8080 -c dynacase -s path/to/sources --auto-release

4.2.2.4 Le résultat

En consultant le contact John DOE à l'adresse http://localhost:8080/api/v1/documents/CONTACT_JOHN_DOE.html, on constate bien que les éléments sont réorganisés en fonction de la résolution.

4.2.3 Utilisation des templates

Dans la partie précédente, nous avons changé la mise en page uniquement au moyen de CSS. Toutefois, il peut être nécessaire d'aller plus loin et de revoir entièrement la disposition des éléments. Dans ce cas, la CSS n'est plus suffisante, et il faut alors passer par des templates.

Il est possible de définir un template pour un attribut en particulier, ou tout ou partie du document (voir le manuel de référence pour plus d'explications sur les templates).

Nous allons définir un template qui surcharge l'intégralité du corps du document pour arriver à ce résultat :

Fiche de contact

Figure 10. Fiche de contact

4.2.3.1 Récupération des sources

Les sources avant cette étape correspondent au tag step-30-20.

4.2.3.2 Code

La première étape est d'indiquer le template à utiliser dans le fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/ContactRenderConfigView.php. Cela se fait au moyen de la méthode getTemplates. Nous allons également injecter 2 fichiers javascript, qui seront utilisés par la suite, au moyen de la méthode getJsReferences. Voici le fichier final :

<?php
 
namespace DduiTuto;
 
class ContactRenderConfigView extends \Dcp\Ui\DefaultView
{
    public function getTemplates(\Doc $document = null)
    {
        $templates = parent::getTemplates($document);
 
        $templates["sections"]["content"]["file"]
            = "DDUI_TUTO/Families/DDUI_TUTO_CONTACT/Layout/contactContent.mustache";
        return $templates;
    }
 
    public function getJsReferences(\Doc $document = null)
    {
        $version = \ApplicationParameterManager::getParameterValue(
            "CORE", "WVERSION"
        );
 
        $jsReferences = parent::getJsReferences();
 
        $jsReferences["bootstrap_collapse"]
            = "lib/bootstrap/3/js/collapse.js?ws="
            . $version;
 
        $jsReferences["jsqr"]
            = "lib/jsqr/jsqr-1.0.2-min.js?ws="
            . $version;
 
        return $jsReferences;
    }
 
    public function getCssReferences(\Doc $document = null)
    {
        $version = \ApplicationParameterManager::getParameterValue(
            "CORE", "WVERSION"
        );
 
        $cssReferences = parent::getCssReferences($document);
 
        $cssReferences['DDUI_TUTO_CONTACT_view']
            = "DDUI_TUTO/Families/DDUI_TUTO_CONTACT/Layout/view.css?ws="
            . $version;
 
        return $cssReferences;
    }
}

Nous pouvons maintenant définir notre template. Ce template utilisera des variables mustache pour récupérer les valeurs du document. Ces variables sont présentées dans le manuel de référence.

Le template ainsi obtenu dans le fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/Layout/contactContent.mustache est le suivant :

<div class="container dc__main">
    <div class="well clearfix">
        <div class="dc__summary">
            <div class="media">
                <div class="media-left media-middle">
                    <img src="{{document.attributes.dc_photo.attributeValue.url}}&width=150"
                         alt="Pas de photo de contact">
                </div>
 
                <div class="media-body">
                    <div class="media">
                        <div class="media-body">
                            <h1 class="media-heading pull-right">
                                {{document.attributes.dc_society.attributeValue.displayValue}}
                            </h1>
                        </div>
                        <div class="media-right media-middle">
                            <img src="{{{document.attributes.dc_logo.attributeValue.thumbnail}}}"
                                 alt="pas de logo de la société">
                        </div>
                    </div>
                    {{{document.attributes.dc_civility.attributeValue.displayValue}}}
                    <h2 class="media-heading">
                        {{{document.attributes.dc_firstname.attributeValue.displayValue}}}
                        {{{document.attributes.dc_lastname.attributeValue.displayValue}}}
                    </h2>
 
                    {{{document.attributes.dc_service.attributeValue.displayValue}}}&nbsp;({{{document.attributes.dc_role.attributeValue.displayValue}}})
                </div>
            </div>
        </div>
        <div id="qrcontainer" class="dc__qrCode"></div>
    </div>
 
    <div class="panel panel-default">
        <div class="panel-heading" role="tab" id="headingMore">
            <h3 class="panel-title">
                <a class="collapsed" role="button" data-toggle="collapse" href="#collapseMore"
                   aria-expanded="true" aria-controls="collapseOne">
                    <i class="collapseMore__icon fa" /> En savoir plus
                </a>
            </h3>
        </div>
        <div id="collapseMore" class="panel-collapse collapse"
             role="tabpanel" aria-labelledby="headingMore">
            <div class="panel-body">
                <div class="row dc__coord">
                    <div class="col-sm-4">
                        <i class="fa fa-phone"></i> {{{document.attributes.dc_workphone.htmlContent}}}
                    </div>
                    <div class="col-sm-4">
                        <i class="fa fa-mobile"></i> {{{document.attributes.dc_mobilephone.htmlContent}}}
                    </div>
                    <div class="col-sm-4">
                        <i class="fa fa-envelope"></i> {{{document.attributes.dc_workmail.htmlContent}}}
                    </div>
                </div>
                <div class="row">
                    <div class="col-sm-6 ">
                        {{{document.attributes.dc_fr_workaddr.htmlView}}}
                    </div>
                    <div class="col-sm-6 ">
                        {{{document.attributes.dc_fr_homeaddr.htmlView}}}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

En bonus dans la version corrigée, vous avez accès au code permettant de générer le QRcode.

Enfin, ce template s'accompagne de CSS. Nous allons donc réécrire le fichier DDUI_TUTO/Families/DDUI_TUTO_CONTACT/Layout/view.css :

.dc__main {
    font-size: 16px;
    padding-top: 20px;
}
 
.dc__coord {
    text-align: center;
}
 
.dc__coord .dcpCustomTemplate--content {
    display: inline-block;
}
 
.dc__coord .fa {
    font-size: 150%;
    vertical-align: top;
    padding-top: 0.2em;
    width: 2em;
    text-align: center;
}
 
.dcpAttribute[data-attrid="dc_workpostalcode"],
.dcpAttribute[data-attrid="dc_workcity"],
.dcpAttribute[data-attrid="dc_homepostalcode"],
.dcpAttribute[data-attrid="dc_homecity"] {
    float: left;
    display: inline-block;
    margin-right: 2px;
}
 
.dcpAttribute__content[data-attrid="dc_workpostalcode"],
.dcpAttribute__content[data-attrid="dc_workcity"],
.dcpAttribute__content[data-attrid="dc_homepostalcode"],
.dcpAttribute__content[data-attrid="dc_homecity"] {
    width: auto;
}
 
.dcpAttribute__label {
    display:none;
}
 
.panel-heading[data-id="dc_fr_workaddr"], /* because of http://dev.dynacase.org/issues/6107 */
.panel-heading[data-attrid="dc_fr_workaddr"],
.panel-heading[data-id="dc_fr_homeaddr"], /* because of http://dev.dynacase.org/issues/6107 */
.panel-heading[data-attrid="dc_fr_homeaddr"] {
    font-size: 14px;
}
 
.collapseMore__icon::before {
    content: "\f0da"; /* fa-caret-right */
}
 
a:not(.collapsed) .collapseMore__icon::before {
    content: "\f0d7"; /* fa-caret-down */
}
 
.panel-title a:hover {
    text-decoration: none;
}
 
.dc__qrCode {
    margin-top: 10px;
    text-align: center;
}
 
@media (min-width:768px) {
    .dc__summary,
    .dc__qrCode {
        float: left;
    }
    .dc__summary {
        width: calc(100% - 210px);
        padding-right: 10px;
    }
    .dc__qrCode {
        width: 210px;
        text-align: right;
        margin-top: 0;
    }
}

4.2.3.3 Déploiement

Les sources telles que déployées à cette étape correspondent au tag step-30-30

Le déploiement se fait au moyen du developer toolkit (pour plus d'explications sur les outils de développement, se rendre sur leur documentation) :

  • pour linux :

    php dynacase-devtool.phar deploy -u localhost -p 8080 -c dynacase -s path/to/sources --auto-release
  • pour windows :

    dynacase-devtool.bat deploy -u localhost -p 8080 -c dynacase -s path/to/sources --auto-release

4.2.3.4 Le résultat

En consultant le contact John DOE à l'adresse http://localhost:8080/api/v1/documents/CONTACT_JOHN_DOE.html, la page ressemble à ce qui était attendu. De plus, le redimensionnement de la page réorganise bien les éléments.

4.3 Conclusion

Vous avez vu dans cette partie qu'il est simple de changer la disposition des éléments d'un document au moyen de CSS, que chaque attribut, ou même chaque sous-élément d'un attribut (libellé, valeur, etc.) est facilement adressable en CSS, et que vous pouvez aussi définir des templates pour des mises en page plus complexes.

De plus, tout ce travail a été accompli en n'écrivant aucun autre php que le code nécessaire pour définir notre template, et ajouter les assets au document.

Dans la partie suivante, nous allons voir comment travailler avec du code Javascript et php pour personnaliser le comportement des documents.

×