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 ![]()
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);
}