J’ai créé un thème plus élaboré pour user-card-contents, en ajoutant quelques champs personnalisés pour les utilisateurs. J’aimerais rendre la carte collante, avec un bouton de fermeture, de manière similaire au composant « Créer un nouveau sujet ».
Ai-je raison de penser que je devrai remplacer user-card-contents.js pour empêcher l’appel qui ferme l’élément ? Serait-il possible d’intégrer cela dans le thème ?
La réponse courte est oui. Si vos modifications n’affectent que le front-end, elles peuvent être effectuées dans un thème ou un composant.
Pourriez-vous préciser ce que vous entendez par « sticky » ? Si vous voulez dire que vous souhaitez qu’il défile avec le contenu tout en restant à la même position, cela nécessiterait une modification CSS. De plus, la modification est-elle destinée à être incluse à la fois sur ordinateur et sur mobile ?
Pourriez-vous décrire précisément à quel appel vous faites référence ? (par exemple, au clic, au défilement, etc.)
Le code HTML du bouton de fermeture devra être ajouté au modèle Handlebars de la carte utilisateur. La logique pour gérer l’action lors du clic sur le bouton devra être ajoutée au fichier .js du composant.
Un remplacement complet pourrait ne pas être nécessaire ; il existe des points d’extension (hooks) que vous pouvez utiliser pour remplacer des méthodes spécifiques dans une classe. Je peux vous en dire plus si vous décrivez un peu plus ce que vous souhaitez faire.
Ce que je cherche à faire, c’est empêcher le gestionnaire d’événements clickOutsideEventName du mixin card-contents-base.js de fermer la carte sur ordinateur. Je préférerais plutôt obliger les utilisateurs à cliquer sur un bouton pour la fermer. Je devrai probablement adopter une approche différente pour mobile.
J’ai réussi à faire fonctionner ce modèle Handlebars, maintenant je vais me pencher sur le fichier .js
Vous connaissez probablement déjà la plupart de ces éléments puisque vous avez déjà travaillé sur votre thème, mais je vais essayer d’être un peu plus précis pour un public plus large.
La première chose à faire est de rechercher localement ou sur GitHub. Sur GitHub, vous obtiendrez quelque chose comme cela. Dans la plupart des cas, un terme de recherche aura plus d’un résultat, et vous devrez soit être plus précis, soit parcourir manuellement les résultats pour trouver quelque chose de proche de ce que vous cherchez.
Ce fichier est un Mixin. Pourquoi le mentionner ? Parce que vous devez savoir que les mixins peuvent être partagés dans de nombreux endroits différents. Dans ce cas, il est utilisé à la fois pour les cartes d’utilisateurs et les cartes de groupes. Ainsi, les modifications que vous apporterez ici affecteront les deux.
Si vous recherchez dans le fichier, vous constaterez que clickOutsideEventName est d’abord défini ici :
Super, mais qu’est-ce que tout cela signifie ? Eh bien, si vous regardez où tout ce code est ajouté, vous remarquerez qu’il se trouve à l’intérieur de didInsertElement :
Ember garantit que, au moment où didInsertElement() est appelé :
L’élément du composant a été à la fois créé et inséré dans le DOM.
L’élément du composant est accessible via la propriété this.element du composant.
Pourquoi avons-nous besoin de cela ? Parce que nous avons besoin d’un gestionnaire de mousedown différent pour les cartes d’utilisateurs et les cartes de groupes. Si nous revenons un peu en arrière, vous remarquerez maintenant que l’ID de l’élément est utilisé dans clickOutsideEventName :
Ce qui, comme nous en avons discuté plus haut, est ensuite transmis en tant que propriété.
Maintenant, passons à la façon dont tout cela se rapporte à ce que vous faites.
Vous essayez d’empêcher les cartes de se fermer lorsque l’utilisateur clique en dehors d’elles. Essayons donc de trouver un moyen de le faire. Si vous vous souvenez, nous avons discuté de la façon dont clickOutsideEventName finit par être consommé ici :
En bref, cela ajoute un gestionnaire mousedown à l’élément HTML lorsqu’une carte est insérée (lors de la première vue de la page). Nous vérifions ensuite la cible de l’événement mousedown. Si la cible se trouve quelque part dans la carte, nous abandonnons. Si elle est en dehors de la carte, nous la fermons en appelant this._close().
Et c’est ce que vous devrez appeler lorsque vous ajouterez votre bouton de fermeture, mais nous y reviendrons plus tard.
Maintenant, l’objectif est de supprimer ce gestionnaire mousedown si vous voulez que les clics en dehors de la carte ne la ferment pas. Comment faisons-nous cela ? Eh bien, nous devrons modifier didInsertElement() et voici comment cela peut être fait.
Les thèmes Discourse ont accès à l’API de plugin, qui contient de nombreuses méthodes que vous pouvez utiliser. Il y a un peu plus de détails sur les plus couramment utilisées ici.
Si vous vous souvenez, le fichier sur lequel nous travaillons est un Mixin. Un Mixin est une classe Ember. Donc, la méthode que nous allons utiliser est modifyClass :
Lorsque vous utilisez modifyClass, vous pouvez ajouter, modifier ou complètement remplacer une méthode de classe. Nous nous concentrerons sur la modification d’une méthode puisque c’est ce que vous voulez faire.
Nous voulons modifier didInsertElement(), donc nous pouvons faire quelque chose comme ceci :
Pourquoi ? Eh bien, il s’avère que la méthode modifyClass ne prend pas actuellement en charge la modification des Mixins (du moins selon mes tests). Je vais noter cela pour comprendre pourquoi c’est le cas et vérifier si nous pouvons corriger cela. Pour l’instant, revenons à ce que vous voulez faire.
Eh bien, nous ne pouvons pas modifier les Mixins, alors je suppose que nous sommes coincés, n’est-ce pas ? Non. Creusons un peu plus profondément.
Comme je l’ai mentionné précédemment, ce Mixin est utilisé à la fois par la carte d’utilisateur user-card-contents et la carte de groupe group-card-contents, des composants Ember (encore une fois, car les Mixins sont conçus pour rendre le code réutilisable).
Donc, regardons le composant user-card-contents ici :
Si vous lisez attentivement, vous remarquerez que nous importons d’abord le Mixin dont nous avons parlé ici
puis nous créons un nouveau composant Ember et lui passons le Mixin.
Qu’est-ce que cela signifie ? Cela signifie que didInsertElement() pour user-card-contents est en fait hérité du Mixin. On peut dire la même chose pour group-card-contents.
Où cela nous laisse-t-il ? Eh bien, il y a une bonne et une mauvaise nouvelle. La bonne nouvelle est que si vous voulez apporter des modifications à user-card-contents sans affecter group-card-contents, vous le pouvez ! La mauvaise nouvelle est que si vous voulez que vos modifications s’appliquent aux deux, vous devrez dupliquer du code.
Revenons à modifyClass et essayons à nouveau avec user-card-contents. Donc quelque chose comme ceci :
La modification est enregistrée et nous pouvons la voir dans la console, mais nous ne sommes pas encore tout à fait là.
Donc, maintenant que nous pouvons modifier didInsertElement(), essayons de revenir à ce que vous essayez de faire. Si vous vous souvenez, le gestionnaire mousedown est défini dans didInsertElement ici :
Vous vous retrouverez avec quelque chose de cassé. Pourquoi ? Parce que ce n’est pas une modification de la méthode. C’est un remplacement complet de la méthode didInsertElement() de base pour ce composant. Ainsi, aucun des codes de base n’est réellement appliqué si vous faites cela.
Comment corriger cela ? Eh bien, il s’avère qu’Ember a quelque chose appelé this._super(...arguments).
Qu’est-ce que cela fait ? Cela vous permet d’ajouter ou de préfixer du code en plus de ce que la méthode de classe a déjà. Par exemple, si vous faites cela :
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// code que vous voulez ajouter
$("html").off(clickOutsideEventName);
// code de base
this._super(...arguments);
}
});
alors le code que vous voulez ajouter sera exécuté avant tout le reste ici :
C’est un excellent moyen de rendre votre thème résistant aux changements dans le code de base, car tout ce qui est dans le code de base s’exécute d’abord, puis votre code s’exécute ensuite. Donc, essayons à nouveau et voyons ce qui se passe.
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// code de base
this._super(...arguments);
// code que vous voulez ajouter
$("html").off(clickOutsideEventName);
}
});
Pourquoi cela se produit-il ? C’est à cause du contexte de code différent. Dans le fichier de composant Ember, clickOutsideEventName est déjà défini au moment où il est consommé. Votre thème est dans un fichier différent, donc clickOutsideEventName n’y est pas défini.
Comment corriger cela ? Vous vous souvenez de ceci ?
clickOutsideEventName est une propriété du composant, donc si vous utilisez this.clickOutsideEventName, cela devrait fonctionner. Essayons cela.
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// code de base
this._super(...arguments);
// code que vous voulez ajouter
$("html").off(this.clickOutsideEventName);
},
});
Et en effet, cela fonctionne
Les cartes d’utilisateurs s’ouvrent maintenant sans erreurs et cliquer n’importe où en dehors ne fait rien.
Vous pouvez faire exactement la même chose pour les cartes de groupes comme ceci :
api.modifyClass('component:group-card-contents', {
didInsertElement() {
// code de base
this._super(...arguments);
// code que vous voulez ajouter
$("html").off(this.clickOutsideEventName);
},
});
La seule chose qui reste est de connecter ce bouton de fermeture à la méthode _close() dont nous avons parlé plus tôt, et cela comporte trois étapes.
Ajouter une action closeCard (vous pouvez lui donner le nom que vous voulez)
Ajouter un bouton au modèle de la carte d’utilisateur
Appeler cette action lorsque le bouton est cliqué.
Je vais m’en tenir aux cartes d’utilisateurs pour plus de simplicité. Donc, nous ajoutons ceci (avec ce que nous avons déjà discuté) :
Et bien sûr, vous pouvez faire quelque chose de similaire pour les cartes de groupes comme je l’ai mentionné plus haut.
Je laisserai l’implémentation pour les cartes de groupes et mobiles comme exercice pour vous, car vous utiliseriez essentiellement exactement les mêmes concepts que nous avons discutés plus haut si vous voulez apporter des modifications à ceux-ci, mais n’hésitez pas à me faire savoir si vous rencontrez des problèmes.} }
Merci beaucoup, cela a fait un excellent tutoriel ! Je vous en suis vraiment reconnaissant. Je n’avais pas réalisé l’existence de l’API des plugins.
Une chose qui n’était pas immédiatement évidente ci-dessus était d’encapsuler les modifications JavaScript du thème dans des balises script et de les placer dans le fichier common/head_tag.html du plugin :
Par simple curiosité, le numéro de version dans la balise a-t-il de l’importance ici ? Et est-il toujours préférable de placer ces éléments dans head_tag.html plutôt que dans header.html, ou cela n’a-t-il pas vraiment d’importance ?