Ajouter une vidéo de fond à certains profils utilisateur ?

Si vous souhaitez ajouter du contenu à une page spécifique, votre meilleure option est un plugin-outlet. En bref, les plugin-outlets sont des espaces réservés dans les modèles Discourse que vous pouvez utiliser pour ajouter du nouveau contenu.

La première chose à faire est de vérifier si un plugin-outlet existe sur la page que vous visez. Il existe un composant de thème que vous pouvez installer pour vous aider dans cette tâche.

(deprecated) Plugin outlet locations theme component

Une fois ce composant installé, activez-le, rendez-vous sur la page cible et vérifiez ce dont vous disposez. Dans votre cas, un tel plugin-outlet existe (mis en évidence en vert).

Celui que nous recherchons est donc above-user-profile.

Supposons qu’il n’existe pas… que faire ? Dans ce cas, la meilleure option est de demander son ajout ou de soumettre une PR pour l’ajouter au cœur du système. Il sera généralement accepté si votre cas d’usage est pertinent.

Quoi qu’il en soit, comme je l’ai dit, il existe déjà dans ce cas. Voyons donc comment y ajouter du code HTML. Vous n’aurez plus besoin du composant mentionné ci-dessus pour la suite, vous pouvez donc le désactiver maintenant puisque vous avez déjà le nom du plugin-outlet.

Tout ce que vous avez à faire est d’ajouter quelque chose comme ceci dans l’onglet En-tête de votre thème.

<script type="text/x-handlebars" data-template-name="/connectors/NOM_DU_OUTLET/NOM_DE_LA_PERSONNALISATION">
  Votre code HTML va ici...
</script>

Vous devez remplacer NOM_DU_OUTLET par le nom de l’outlet que vous visez. Ensuite, remplacez NOM_DE_LA_PERSONNALISATION par le nom que vous souhaitez donner à cette personnalisation. Le nom peut être n’importe quoi, mais essayez d’être descriptif si possible. C’est une bonne pratique. Nous obtenons donc ceci :

<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
  Votre code HTML va ici... comme
  <h1>Bonjour le monde !!</h1>
</script>

Essayons cela et voyons ce qui se passe… rappelez-vous, l’extrait ci-dessus va dans l’onglet common > header de votre thème.

et…

Jusqu’ici tout va bien, mais creusons un peu plus.

Vous ne voulez pas que vos vidéos s’affichent sur tous les profils, mais uniquement selon certaines conditions. Comment faire ? Vous aurez besoin de deux choses : des données à consommer et un peu de JavaScript.

Trouvons les données. Vous vous souvenez quand j’ai dit que les plugin-outlets sont des espaces réservés ? Quel est l’intérêt de les avoir sans contexte ? C’est pourquoi Discourse transmet les éléments de contexte pertinents à chaque plugin-outlet… mais d’abord, faisons un pas en arrière. Lorsque vous ajoutez ceci :

<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
  Votre code HTML va ici, comme...
  <h1>Bonjour le monde !!</h1>
</script>

Cela ressemble à du HTML – et les balises script le sont – mais ce qu’elles contiennent est traité comme du code Handlebars.

Cela signifie que vous pouvez faire quelque chose comme ceci à la place :

<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
  {{log this}}
</script>

et vérifiez la console du navigateur. Vous verrez ceci chaque fois que l’outlet est rendu, c’est-à-dire lorsque vous êtes sur une page utilisateur.

Maintenant, est-ce que l’un de ces éléments est utile ? Oui… mais pas pour le moment. Nous y reviendrons. Faisons un autre pas en arrière et voyons comment Discourse transmet le contexte à l’outlet. Si vous recherchez le nom de l’outlet sur GitHub – ou localement – vous obtiendrez ceci :

Repository search results · GitHub

Ouvrons ce fichier. La première chose que vous voyez est cette ligne :

Regardez la dernière partie de cette ligne :

args=(hash model=model)

Vous verrez que Discourse transmet model en tant qu’argument à l’outlet. Pour tous les intents et purposes et pour garder les choses simples, model = data.

Donc, l’un des arguments de notre outlet est model, et c’est là que se trouvent les données que nous voulons. Revenons donc à notre extrait.

<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
  {{log this}}
</script>

et changeons-le en ceci :

<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
-  {{log this}}
+  {{log args}}
</script>

Nous obtenons maintenant ceci dans la console.

Vous pouvez parcourir ces données et voir si elles contiennent ce dont vous avez besoin. Elles devraient, car elles contiennent toutes les données sur l’utilisateur utilisées dans d’autres éléments de cette page. C’est le « modèle » pour la page utilisateur de cet utilisateur particulier.

L’une des propriétés disponibles là-bas est… roulement de tambour :drum: … les groupes auxquels l’utilisateur appartient.

Donc, si vous faites :

{{log args.model.groups}}

vous obtiendrez tous les groupes auxquels l’utilisateur appartient dans la console.

Bon, maintenant nous avons les données dont nous avons besoin, il ne nous reste plus qu’à ajouter une ou plusieurs conditions basées là-dessus.

Vous pourriez être tenté de penser que nous pouvons le faire dans le même extrait, mais malheureusement, nous ne pouvons pas. Handlebars est un langage de modélisation. Il prend en charge très, très basiquement la logique – rien au-delà de simples conditions vrai/faux et de boucles. Vous ne pouvez pas faire de comparaisons et autres choses comme ça.

Alors où exactement pouvez-vous le faire ? Dans une classe de connecteur, ça sonne fancy… je sais.

En bref, une classe de connecteur est essentiellement un peu de JavaScript attaché à l’outlet. C’est beaucoup plus nuancé que cela, mais c’est tout ce dont vous avez vraiment besoin pour l’instant.

Créons-en une. Nous le faisons ainsi :

<script type="text/discourse-plugin" version="0.8">
api.registerConnectorClass('NOM_DU_OUTLET', 'NOM_DE_LA_PERSONNALISATION', {

});
</script>

NOM_DU_OUTLET et NOM_DE_LA_PERSONNALISATION ici doivent être les mêmes que ceux utilisés ci-dessus. Changeons-les donc :

<script type="text/discourse-plugin" version="0.8">
api.registerConnectorClass('above-user-profile', 'add-profile-videos', {

});
</script>

Cet extrait va également dans l’onglet common > header de votre thème. Vous devriez donc maintenant avoir quelque chose qui ressemble à ceci :

<script type="text/x-handlebars" data-template-name="/connectors/above-user-profile/add-profile-videos">
  {{log args.model.groups}}
</script>

<script type="text/discourse-plugin" version="0.8">
  api.registerConnectorClass('above-user-profile', 'add-profile-videos', {

  });
</script>

Dans notre classe de connecteur, nous pouvons faire du travail… mais… nous devons être conscients que ce n’est pas comme n’importe quel fichier JavaScript. Par manque de meilleure description… pensez-y comme un composant Ember en régime. Développer cela est un peu hors du cadre ici, alors passons.

Il y a quatre méthodes connectées par défaut :

actions vous permet de définir des actions comme suit :

api.registerConnectorClass("above-user-profile", "add-profile-videos", {
  actions: {
    myAction() {
      // faire quelque chose
    }
  }
});

Vous pouvez ensuite appeler cette action depuis l’outlet, par exemple lorsqu’un bouton est pressé. Nous n’en aurons pas besoin ici, alors passons.

api.registerConnectorClass("above-user-profile", "add-profile-videos", {
  shouldRender(args, component) {
    // renvoyer true ou false ici
  }
});

Nous n’utiliserons pas celle-ci non plus, car l’outlet ne se rend que sur les pages de profil, et nous n’avons pas d’autres exigences pour l’instant. Cependant, vous pouvez l’utiliser pour ajouter toutes les conditions que vous souhaitez tester avant que l’outlet ne soit rendu. Par exemple, le niveau de confiance de l’utilisateur actuel ou autre chose comme ça. Continuons…

api.registerConnectorClass("above-user-profile", "add-profile-videos", {
  setupComponent(args, component) {
    // faire quelque chose
  }
});

C’est celle sur laquelle nous voulons nous concentrer. Toutes les conditions JavaScript ou variables que vous souhaitez définir vont ici. Avant d’approfondir celle-ci, couvrons d’abord la dernière méthode pour être complet :

api.registerConnectorClass("above-user-profile", "add-profile-videos", {
  teardownComponent(args, component) {
    // faire quelque chose
  }
});

Cela se déclenche lorsque l’outlet va être supprimé. Cela vous permet donc d’effectuer tout nettoyage nécessaire, comme supprimer les écouteurs d’événements, etc.

Ok, revenons à setupComponent :

api.registerConnectorClass("above-user-profile", "add-profile-videos", {
  setupComponent(args, component) {
    // faire quelque chose
  }
});

Vous pouvez voir qu’il y a deux éléments qui lui sont passés. D’abord, il y a args, puis component.

args ici est la même chose que nous avons examinée plus tôt. Ce sont les données de contexte que Discourse a transmises à l’outlet. Donc, si vous faites :

api.registerConnectorClass("above-user-profile", "add-profile-videos", {
  setupComponent(args, component) {
    console.log(args.model.groups);
  }
});

vous verrez les mêmes informations dans la console du navigateur que nous avons vues précédemment. Les groupes auxquels appartient le propriétaire du profil. C’est là que ça devient intéressant, vous avez maintenant les données et le bon crochet. Vous pouvez donc faire ce que vous voulez ici. Donc, si je veux que la vidéo ne s’affiche que sur les profils des membres appartenant à un certain groupe, je peux faire ceci :

  api.registerConnectorClass('above-user-profile', 'add-profile-videos', {
    setupComponent(args, component) {
      const inGroup = [...args.model.groups].filter(g => g.name === TARGET_GROUP)
      const showVideo = inGroup.length ? true : false;

      console.log(showVideo);
    }
  });

Si vous essayez cela sur une page de profil appartenant à un utilisateur du groupe staff, cela affichera true dans la console. Donc, maintenant, la seule chose qui nous reste à faire est de transmettre cela au modèle de l’outlet. Voici comment vous pouvez le faire.

component passé à setupComponent ici est partagé entre le connecteur et l’outlet. Vous pouvez transmettre des choses à l’outlet en les définissant comme des propriétés sur le composant comme suit :

  const TARGET_GROUP = "staff"

  api.registerConnectorClass('above-user-profile', 'add-profile-videos', {
    setupComponent(args, component) {
      const inGroup = [...args.model.groups].filter(g => g.name === TARGET_GROUP)
      const showVideo = inGroup.length ? true : false;
-     console.log(showVideo);
+     component.setProperties({showVideo})
    }
  });

Maintenant, si nous retournons au modèle et faisons quelque chose comme :

{{log showVideo}}

cela affichera le même résultat. Nous pouvons donc maintenant le mettre dans une condition Handlebars et ajouter votre code HTML à l’intérieur comme ceci :

<script
  type="text/x-handlebars"
  data-template-name="/connectors/above-user-profile/add-profile-videos"
>
  {{#if showVideo}}
    <video playsinline autoplay muted loop id="myVideo" poster="[INSÉRER LE LIEN]">
  	  <source src="[INSÉRER LE LIEN]" type="video/webm">
  	  <source src="[INSÉRER LE LIEN]" type="video/mp4">
    </video>
  {{/if}}
</script>

Ensuite, vérifiez une page de profil pour un utilisateur staff. Vous verrez que la vidéo se charge.

Une fois que vous naviguez hors du profil du membre du staff, la vidéo disparaîtra. La vidéo ne s’affichera pas sur les profils des utilisateurs qui ne sont pas dans le groupe staff.

Alors, mettons tout cela ensemble. C’est la même chose que ci-dessus.

Voici le CSS que j’ai utilisé. Onglet common > css :

#myVideo {
  position: fixed;
  top: var(--header-offset);
  min-height: 100vh;
  left: 0;
  z-index: -1;
}

.user-content {
  background: none;
}

.user-main {
  padding: 0.5em;
  background: rgba(var(--secondary-rgb), 0.8);
}

// si vous voulez que cela fonctionne aussi sur mobile
.mobile-view {
  body[class*="user-"] {
    background: none;
    .user-main,
    .user-content {
      padding: 0.5em;
      background: rgba(var(--secondary-rgb), 0.8);
    }
  }
}

HTML / JavaScript / Handlebars. Cela va dans l’onglet common > header de votre thème :

<script
  type="text/x-handlebars"
  data-template-name="/connectors/above-user-profile/add-profile-videos"
>
  {{#if showVideo}}
    <video playsinline autoplay muted loop id="myVideo" poster="[INSÉRER LE LIEN]">
  	  <source src="[INSÉRER LE LIEN]" type="video/webm">
  	  <source src="[INSÉRER LE LIEN]" type="video/mp4">
    </video>
  {{/if}}
</script>

<script type="text/discourse-plugin" version="0.8">
  const TARGET_GROUP = "staff"

  api.registerConnectorClass('above-user-profile', 'add-profile-videos', {
    setupComponent(args, component) {
      const inGroup = [...args.model.groups].filter(g => g.name === TARGET_GROUP)
      const showVideo = inGroup.length ? true : false;
      component.setProperties({showVideo})
    }
  });
</script>

Remplacez TARGET_GROUP par le nom du groupe que vous souhaitez cibler et ajoutez les attributs src pour vos vidéos.

Ce post était un peu long… ne vous laissez pas décourager par cela. Une fois que vous avez compris le concept, tout ce que nous avons fait ci-dessus peut être fait en moins de 3 à 5 minutes.

La chose sympa ici est que tout ce dont nous avons parlé est à peu près le même pour n’importe quel plugin-outlet. La seule chose qui change est le nom. Donc, cela s’applique à toutes les modifications de plugin-outlet que vous souhaitez effectuer à l’avenir.

  1. Trouvez le nom de l’outlet
  2. Obtenez les données
  3. Traitez les données dans un connecteur
  4. Renvoyez les propriétés au modèle