TL;DR Creo que esto es lo que buscas
Theme JS
api.modifyClass("component:user-card-contents", {
didInsertElement() {
this._super(...arguments);
$("html").off(this.clickOutsideEventName);
},
actions: {
closeCard() {
this._close();
}
}
});
y luego añade esto a tu plantilla en algún lugar
{{d-button
class="btn-flat"
action=(action "closeCard")
icon="times"
}}
La versión larga
Probablemente ya sepas la mayoría de esto, ya que ya has trabajado en tu tema, pero intentaré mantenerlo un poco más detallado para una audiencia más amplia.
Lo primero que haría es buscar, ya sea localmente o en Github. En Github obtendrías algo como esto. En la mayoría de los casos, un término de búsqueda tendrá más de un resultado y tendrás que ser más específico o escanear manualmente los resultados para encontrar algo cercano a lo que buscas.
Así que, ahora terminamos en este archivo
Este archivo es un Mixin. ¿Por qué lo menciono? Porque debes ser consciente de que los mixins se pueden compartir en varios lugares diferentes. En este caso, se utiliza tanto para tarjetas de usuario como para tarjetas de grupo. Por lo tanto, los cambios que realices aquí afectarán a ambas.
Si buscas en el archivo, encontrarás que clickOutsideEventName se define primero aquí
luego se pasa aquí como una propiedad
y finalmente se consume aquí
Genial, pero ¿qué significa todo eso? Bueno, si miras dónde se agrega todo este código, notarás que está dentro de didInsertElement
Las guías de Ember establecen
Ember garantiza que, cuando se llama a
didInsertElement():
- El elemento del componente se ha creado e insertado en el DOM.
- El elemento del componente es accesible a través de la propiedad
this.elementdel componente.
¿Por qué necesitamos esto? Porque necesitamos un manejador de mousedown diferente para las tarjetas de usuario y las tarjetas de grupo. Si volvemos un poco atrás, ahora notarás que el id del elemento se utiliza en clickOutsideEventName
Lo cual, como discutimos anteriormente, luego se pasa como una propiedad.
Ahora, pasemos a cómo todo esto se relaciona con lo que estás haciendo.
Estás intentando evitar que las tarjetas se cierren cuando el usuario hace clic fuera de ellas. Así que intentemos encontrar una manera de hacer eso. Si recuerdas, discutimos cómo clickOutsideEventName finalmente se consume aquí
En resumen, esto agrega un manejador de mousedown al elemento HTML cuando se inserta una tarjeta (en la primera vista de página). Luego verificamos el objetivo del evento mousedown. Si el objetivo está en algún lugar de la tarjeta, nos retiramos. Si está fuera de la tarjeta, la cerramos llamando a this._close()
_close() se define aquí
Y esto es lo que necesitarás llamar cuando agregues tu botón de cerrar, pero volveremos a eso más tarde.
Ahora, el objetivo es eliminar este manejador de mousedown si quieres que los clics fuera de la tarjeta no la cierren. ¿Entonces cómo lo hacemos? Bueno, necesitaremos modificar didInsertElement() y así es como se puede hacer.
Los temas de Discourse tienen acceso a la API de plugins, que contiene muchos métodos que puedes usar. Hay un poco más de detalles sobre los más comúnmente utilizados aquí
Si recuerdas, el archivo con el que estamos trabajando es un Mixin. Un Mixin es una clase de Ember. Por lo tanto, el método que vamos a usar es modifyClass
Cuando usas modifyClass, puedes agregar, modificar o anular completamente un método de clase. Nos centraremos en modificar un método, ya que eso es lo que quieres hacer.
Queremos modificar didInsertElement(), así que podemos hacer algo como esto
api.modifyClass('mixin:card-contents-base', {
didInsertElement() {
console.log("foo");
}
});
y probarlo…
bueno, eso no funcionó.
¿Por qué es eso? Resulta que el método modifyClass actualmente no admite la modificación de Mixins (hasta donde he probado). Haré una nota para averiguar por qué es así y verificar si podemos solucionarlo. Por ahora, volvamos a lo que quieres hacer.
Bueno, no podemos modificar Mixins, así que supongo que estamos atascados, ¿verdad? No. Profundicemos un poco más.
Como mencioné antes, ese Mixin es utilizado tanto por el usuario user-card-contents como por group-card-contents, componentes de Ember components (de nuevo, porque los Mixins están diseñados para hacer el código reutilizable).
Así que, veamos el componente user-card-contents aquí
Si lees atentamente, notarás que primero importamos el Mixin que discutimos anteriormente aquí
y luego creamos un nuevo componente de Ember y le pasamos el Mixin.
¿Qué significa eso? Significa que didInsertElement() para user-card-contents se hereda realmente del Mixin. Lo mismo se puede decir de group-card-contents.
¿Dónde nos deja eso? Bueno, hay buenas y malas noticias. La buena noticia es que si quieres hacer cambios en user-card-contents sin afectar a group-card-contents, ¡puedes hacerlo! La mala noticia es que si quieres que tus cambios se apliquen a ambos, entonces tendrás que duplicar algo de código.
Volvamos a modifyClass e intentémoslo de nuevo con user-card-contents. Así que algo como esto:
api.modifyClass('component:user-card-contents', {
didInsertElement() {
console.log("foo");
}
});
y veamos qué pasa…
voilá ![]()
El cambio se registra y podemos verlo en la consola, pero aún no hemos llegado del todo.
Así que, ahora que podemos modificar didInsertElement(), intentemos volver a lo que estás intentando hacer. Si recuerdas, el manejador de mousedown se define en didInsertElement aquí
¿Entonces qué podemos hacer al respecto? Bueno, es tan simple como esto
$("html").off(clickOutsideEventName)
¿Funcionará eso? No. Si haces esto
api.modifyClass('component:user-card-contents', {
didInsertElement() {
$("html").off(clickOutsideEventName)
}
});
terminarás con algo roto. ¿Por qué es eso? Porque eso no es una modificación del método. Es una anulación completa del método central didInsertElement() para ese componente. Por lo tanto, si haces esto, no se aplica realmente ningún código del núcleo.
¿Cómo lo solucionamos? Resulta que Ember tiene algo llamado this._super(...arguments)
¿Qué hace eso? Te permite agregar o prependir código además de lo que ya tiene el método de la clase. Por ejemplo, si haces esto
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// código que quieres agregar
$("html").off(clickOutsideEventName);
// código del núcleo
this._super(...arguments);
}
});
entonces el código que quieres agregar se ejecutará antes que cualquier otra cosa aquí
Sin embargo, si haces esto…
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// código del núcleo
this._super(...arguments);
// código que quieres agregar
$("html").off(clickOutsideEventName);
}
});
entonces tu código se ejecutará después de que todo esto se ejecute
Esta es una gran manera de mantener tu tema resistente a los cambios en el núcleo, ya que todo en el núcleo se ejecuta primero y luego tu código se ejecuta después. Así que intentémoslo de nuevo y veamos qué pasa.
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// código del núcleo
this._super(...arguments);
// código que quieres agregar
$("html").off(clickOutsideEventName);
}
});
y…
¿Por qué está sucediendo esto? Es debido a un contexto de código diferente. En el archivo del componente de Ember, clickOutsideEventName ya está definido cuando se consume. Tu tema está en un archivo diferente, por lo que clickOutsideEventName no está definido allí.
¿Cómo lo solucionamos? ¿Recuerdas esto?
clickOutsideEventName es una propiedad del componente, por lo que si usas this.clickOutsideEventName, debería funcionar. Probémoslo.
api.modifyClass('component:user-card-contents', {
didInsertElement() {
// código del núcleo
this._super(...arguments);
// código que quieres agregar
$("html").off(this.clickOutsideEventName);
},
});
Y de hecho funciona ![]()
Las tarjetas de usuario ahora se abren sin errores y hacer clic en cualquier lugar fuera no hace nada.
Puedes hacer exactamente lo mismo para las tarjetas de grupo de la siguiente manera
api.modifyClass('component:group-card-contents', {
didInsertElement() {
// código del núcleo
this._super(...arguments);
// código que quieres agregar
$("html").off(this.clickOutsideEventName);
},
});
Lo único que queda es conectar ese botón de cerrar al método _close() que discutimos anteriormente y hay tres pasos para esto.
- agregar una acción
closeCard(puedes nombrarla como quieras) - agregar un botón a la plantilla de la tarjeta de usuario
- llamar a esa acción cuando se haga clic en el botón.
Me quedaré con las tarjetas de usuario por simplicidad. Así que, agregamos esto (junto con lo que ya discutimos)
api.modifyClass("component:user-card-contents", {
didInsertElement() {
this._super(...arguments);
$("html").off(this.clickOutsideEventName);
},
// cosas nuevas
actions: {
closeCard() {
this._close();
}
}
});
todo lo que hace es llamar al método _close() del núcleo cada vez que se activa la acción personalizada closeCard.
A continuación, necesitamos agregar un botón a la plantilla de la tarjeta de usuario o algo así
{{d-button
class="btn-flat"
action=(action "closeCard")
icon="times"
}}
Mis resultados aproximados se ven así
Y, por supuesto, puedes hacer algo similar para las tarjetas de grupo como mencioné anteriormente.
Dejaré la implementación de la tarjeta de grupo y móvil como ejercicio para ti, ya que esencialmente usarías los mismos conceptos que discutimos anteriormente si quieres hacer cambios en ellos, pero por favor házmelo saber si tienes algún problema.


