TL;DR Je pense que c’est ce que vous cherchez
JS du thème
api.modifyClass("component:user-card-contents", {
didInsertElement() {
this._super(...arguments);
$("html").off(this.clickOutsideEventName);
},
actions: {
closeCard() {
this._close();
}
}
});
Ensuite, ajoutez ceci quelque part dans votre modèle :
{{d-button
class="btn-flat"
action=(action "closeCard")
icon="times"
}}
La version détaillée
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.
Nous aboutissons donc à ce fichier :
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 :
puis transmis ici en tant que propriété :
et enfin consommé 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 :
Les guides Ember indiquent :
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.elementdu 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().
_close() est défini ici :
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 :
api.modifyClass('mixin:card-contents-base', {
didInsertElement() {
console.log("foo");
}
});
et essayer…
eh bien, cela n’a pas fonctionné.
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 :
api.modifyClass('component:user-card-contents', {
didInsertElement() {
console.log("foo");
}
});
et voyons ce qui se passe…
voilá ![]()
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 :
Alors, que pouvons-nous faire à ce sujet ? Eh bien, c’est aussi simple que cela :
$("html").off(clickOutsideEventName)
Cela fonctionnera-t-il ? Non. Si vous faites cela :
api.modifyClass('component:user-card-contents', {
didInsertElement() {
$("html").off(clickOutsideEventName)
}
});
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 :
Cependant, si vous faites cela…
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// code de base
this._super(...arguments);
// code que vous voulez ajouter
$("html").off(clickOutsideEventName);
}
});
alors votre code sera exécuté après que tout cela ait été exécuté :
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);
}
});
et…
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é) :
api.modifyClass("component:user-card-contents", {
didInsertElement() {
this._super(...arguments);
$("html").off(this.clickOutsideEventName);
},
// nouveau contenu
actions: {
closeCard() {
this._close();
}
}
});
Tout ce que cela fait, c’est appeler la méthode _close() de base chaque fois que l’action personnalisée closeCard est déclenchée.
Ensuite, nous devons ajouter un bouton au modèle de la carte d’utilisateur ou quelque chose comme ceci :
{{d-button
class="btn-flat"
action=(action "closeCard")
icon="times"
}}
Mes résultats approximatifs ressemblent à ceci :
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.} }


