Notification de nouveau ou mis à jour sujet épinglé

Bonjour,

Cela pourrait être utile si l’élément Voir x nouveaux ou mis à jour sujets était fixé en haut, juste sous l’en-tête, afin que vous le voyiez immédiatement en faisant défiler la liste des sujets. Lorsque vous cliquez sur cette barre, la page devrait remonter en haut pour charger les nouveaux ou mis à jour sujets.

La partie fixée fonctionne très bien avec ceci : :arrow_down:

#list-area .show-more.has-topics {
  position: sticky;
  top: var(--header-offset);
}

L’autre partie (JavaScript) consisterait en une fonction de clic pour remonter en haut ou faire défiler jusqu’au sommet, mais je ne sais pas comment le faire ni quelle est la meilleure méthode.

J’ai trouvé cette section dans les modèles discovery/topics.hbs et discovery/categories.hbs. Si je modifie le <a href en <a href="/", cela pourrait fonctionner (je ne suis pas sûr, je n’ai pas essayé), mais cela rechargerait la page à chaque fois, comme si je cliquais sur le logo.

Merci pour votre aide :slightly_smiling_face:

Oui, l’ajout d’une URL provoquera une navigation car il n’existe aucune logique pour intercepter l’événement.

Le lien appelle une action Ember. Toutes les actions dans Discourse sont extensibles. Elles agissent donc en quelque sorte comme des points d’extension pour la personnalisation. Alors, comment modifier une action ? Eh bien, vérifions d’abord ce qu’elle fait.

Recherchez sur GitHub ou localement le nom de l’action. Les actions sont toujours définies dans des fichiers JS et référencées dans Handlebars. Nous voulons voir la définition, nous restreignons donc la recherche aux fichiers JS.

Repository search results · GitHub

Vous obtenez quatre fichiers. Lequel devez-vous examiner ? Vous souhaitez personnaliser le
template
discovery/topics.hbs
. Donc,
discovery/topics.js
est ce que vous devez examiner.

Ce code est-il utile ? Non, mais nous savons maintenant où l’action est définie. Modifions-la donc.

discovery/topics.js est une classe Ember. Vous pouvez modifier les classes Ember avec une méthode dans l’API des plugins appelée… modifyClass :stuck_out_tongue:

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L166-L195

Nous connaissons déjà la classe que nous voulons modifier. C’est discovery/topics. Nous devons savoir de quel type de classe il s’agit. Vérifions donc le répertoire des fichiers.

discourse/app/controllers/discovery/topics.js

C’est un contrôleur.

Nous savons également que nous voulons modifier l’action showInserted dans cette classe. Commençons donc par ceci.

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
      // faisons quelques travaux
    }
  }
});

Vous pouvez ensuite ajouter tout code que vous souhaitez pour faire défiler la fenêtre lorsque l’utilisateur clique sur la bannière « nouveaux sujets ». J’ai opté pour quelque chose comme ceci.

const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();

Vous pouvez en savoir plus sur scrollIntoView() ici.

Ensuite, vous ajoutez cela à la méthode de l’API des plugins comme suit.

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
+     const listControls = document.querySelector(".list-controls");
+     listControls.scrollIntoView();
    }
  }
});

Alors, avons-nous terminé ? Non. Cela brise Discourse car vous remplacez complètement l’action. Cliquer sur le lien fera maintenant défiler vers l’élément list-controls, mais il ne chargera pas les nouveaux sujets. Pourquoi ? Parce que le code principal n’est plus appliqué. Je veux dire, ce genre de chose

Alors, comment corriger cela ? Avec cette ligne simple

this._super(...arguments);

Vous n’avez pas besoin de copier du code depuis le noyau si vous souhaitez simplement y ajouter quelque chose. Faites votre travail, puis ajoutez cette ligne. Tout ce qu’elle fait, c’est s’assurer que le code du noyau est appliqué.

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
     const listControls = document.querySelector(".list-controls");
     listControls.scrollIntoView();
+
+    this._super(...arguments);
    }
  }
});

Si vous testez cela, vous verrez que presque tout fonctionne parfaitement, sauf… l’en-tête chevauche list-controls. Pourquoi ? Parce que l’en-tête est défini comme sticky.

Vous pouvez corriger cela de plusieurs façons en JS : calculer la hauteur, obtenir le décalage, importer un helper depuis Discourse, etc. Je n’entrerai pas dans ces détails.

La méthode la plus simple consiste à utiliser CSS avec scroll-margin-top, dont vous pouvez lire la documentation ici.

Nous ajoutons donc ceci

.list-controls {
  scroll-margin-top: calc(var(--header-offset) * 2);
}

En français : Lorsque le lien est cliqué, faites défiler jusqu’au haut de list-controls - 2 * la hauteur de l’en-tête, afin qu’il ne chevauche pas et qu’il y ait un peu d’espace en dessous.

Mettons donc tout cela ensemble.

Onglet En-tête commun

<script type="text/discourse-plugin" version="0.8">
api.modifyClass("controller:discovery/topics", {
  pluginId: "sticky-new-topics-banner",
  actions: {
    showInserted() {
      const listControls = document.querySelector(".list-controls");
      listControls.scrollIntoView();
      this._super(...arguments);
    }
  }
});
</script>

CSS commun

#list-area {
  // mobile a une mise en page différente
  .alert-info,
  .show-more.has-topics {
    position: sticky;
    // safari est parfois capricieux sans le préfixe
    position: -webkit-sticky;
    top: var(--header-offset);
    // la bannière doit être au-dessus du contenu
    z-index: z("header");
  }
}

.list-controls {
  scroll-margin-top: calc(var(--header-offset) * 2);
}

Merci @Johani ! Cela m’a été très utile et je pense avoir enfin compris beaucoup de choses. J’apprécie vraiment tes réponses détaillées car on peut beaucoup apprendre grâce à elles : comment les choses fonctionnent et, bien sûr, que tout fonctionne parfaitement. Merci encore ! :slightly_smiling_face: