He creado un tema más elaborado para user-card-contents, añadiendo algunos campos de usuario personalizados. Me gustaría hacer que la tarjeta sea fija, con un botón de cierre, de manera similar al componente “Crear un nuevo tema”.
¿Tengo razón al pensar que tendré que sobrescribir user-card-contents.js para evitar la llamada que cierra el elemento? ¿Podría empaquetar esto dentro del tema?
La respuesta corta es sí. Si tus cambios solo afectan al front-end, entonces se pueden realizar en un tema o componente.
¿Podrías detallar a qué te refieres con “fijo”? Si te refieres a que quieres que se desplace junto con el contenido manteniéndose en la misma posición, eso sería un cambio de CSS. Además, ¿se pretende que el cambio esté incluido tanto en escritorio como en móvil?
¿Podrías describir específicamente a qué llamada te refieres? (por ejemplo, al hacer clic, al desplazarse, etc.)
El marcado para el botón de cerrar tendría que añadirse a la plantilla Handlebars de la tarjeta de usuario. La lógica para manejar la acción cuando se hace clic en el botón tendría que añadirse al archivo .js del componente.
Es posible que no sea necesaria una sobrescritura completa; hay algunos ganchos (hooks) que puedes usar para sobrescribir métodos específicos en una clase. Puedo compartir más información sobre eso si describes un poco más lo que quieres hacer.
Lo que busco hacer es evitar que el controlador de eventos clickOutsideEventName del mixin card-contents-base.js cierre la tarjeta en escritorio. En su lugar, me gustaría obligar a los usuarios a hacer clic en un botón para cerrarla. Probablemente necesite hacer algo diferente para móvil.
Ya logré que funcione esta plantilla de Handlebars, ahora a averiguar lo del archivo .js
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.
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í
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.element del 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()
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
¿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:
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í
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í
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);
}
});
¿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)
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.
¡Muchas gracias, esto ha resultado en un excelente tutorial! Lo aprecio mucho. No había dado cuenta de la API de complementos.
Una cosa que no era inmediatamente obvia arriba fue envolver los cambios de JS del tema en etiquetas de script y colocarlo en common/head_tag.html del complemento:
Solo por curiosidad, ¿importa el número de versión en la etiqueta aquí? ¿Y es siempre mejor colocarlos en head_tag.html en lugar de header.html o realmente no importa.