Cambiar avatar y nombre de usuario en una publicación específica

El problema: quiero que los usuarios puedan publicar como personajes de RPG. Me gustaría que pudieran insertar una plantilla en una publicación, algo como lo siguiente:

[wrap="characterpost"]
[characterav]https://image.link.example.png[/characterav]
[charactername][[Character Name]][/charactername]
[/wrap]

Y luego usar un script para que la imagen reemplace el avatar original y el enlace del tema del nombre del personaje aparezca antes del nombre de usuario. Por ejemplo, si la publicación normalmente dice «Username», quiero reemplazarlo por «Character Name played by Username».
(«Character Name» incluiría un enlace a un tema con la ficha del personaje, usando idealmente solo el componente de tema de wikilinks por facilidad de uso.)

Pegué un esqueleto de publicación en Codepen y logré escribir algo de JavaScript que haría exactamente esto. Sin embargo, cuando intenté agregarlo en un decorador de publicaciones y hacerlo funcionar en vivo con la API, me topé con un muro.

Esto es lo que tengo en common>header ahora mismo:

<script type="text/discourse-plugin" version="0.8">
api.decorateCookedElement(
  element => {
    
    // find the characterpost tag within the post
    const characterPost = element.querySelector('[data-wrap="characterpost"]');
	
    // find the parent of the characterpost tag, which contains avatar and username
    const characterPostParent = characterPost.closest('article');
	
    // turn it red to see if it's working
    characterPostParent.style.backgroundColor = "red";
    
  },
  {
    id: 'render-character-post', onlyStream: true, afterAdopt: true
  }
);
</script>

Esto ha estado lanzando un error. ¿Es posible acceder al envoltorio «article» de las publicaciones usando decorateCookedElement para que pueda obtener el nombre de usuario y el avatar? Si no, ¿cómo puedo abordarlo?

Hola, unfairest,

¡Me encontré con esta publicación y pensé que podría intentarlo!

Aquí está la primera versión; espero que el código no sea demasiado horrible. :slightly_smiling_face:
No probé exhaustivamente todos los casos extremos. Es un punto de partida.

  • Formato de envoltura esperado: [wrap=character avatar=\"<URL>\"]<Nombre>[/wrap]
  • Asegúrate de que haya una línea vacía debajo de [wrap]
  • Puedes personalizar el nombre del personaje con CSS (consulta las clases character y character-extra)

Avísame si tienes algún problema :slight_smile:

Head
<script type="text/discourse-plugin" version="0.8.13">

let characters = new Map();

function searchTag(obj, tag) {
  if (!obj || !obj.firstObject) return;
  
  const firstObj = obj.firstObject;
  return firstObj.tagName === tag ? firstObj : searchTag(firstObj.children, tag);
}
            
api.addPostTransformCallback(post => 
{
    if (post.post_number <= 1 || post.post_type !== 1) {
        return;
    }

    const matches = post.cooked.match(/data-wrap="character"\s+data-avatar="(?<avatar>[^"]+)"\s+data-name="(?<name>[^"]+)"/i);
    
    if (!matches) {
        characters.delete(post.id);
        return;
    }
    
    // TODO: sanity check for avatar/name
    
    const {name, avatar} = matches.groups;
    
    characters.set(post.id, {name, avatar});
    
});

api.reopenWidget("post-avatar", {
    html(attrs) {
        const html = this._super(attrs);
        
        if (attrs.id && characters.has(attrs.id)) {
            const imageHtml = searchTag(html, 'IMG');
    
            if (imageHtml) {
                imageHtml.properties.attributes.src = characters.get(attrs.id).avatar;
            }
        }
        
        return html;
    }
});

api.reopenWidget("poster-name", {
    html(attrs) {
        let html = this._super(attrs);
        
        if (attrs.id && characters.has(attrs.id)) {
            const h = require("virtual-dom").h;
            
            html = [
                h('span.character', this.userLink(attrs, characters.get(attrs.id).name)),
                h('span.character-extra', 'played by'), // optional
                ...html
            ];
        }
        
        return html;
    }
});

</script>
CSS
.names {
    .character a {
        font-weight: bold;
        color: var(--tertiary-high);
    }
    
    .character-extra {
        
    }
}

.cooked, .d-editor-preview {
    p:has(> [data-wrap="character"]) {
        display: none;
    }
    
    p:has(> [data-wrap="character"]) + * {
        margin-top: 0;
    }
}

Aquí hay una pequeña demostración de cómo se veía:

¡Esto es muy genial, gracias por compartir! Yo también estaba buscando algo similar. ¿Sabes si esto también afecta cómo aparecen las publicaciones en la búsqueda?

¡Buena pregunta! El nombre de la etiqueta y su contenido forman parte del contenido de la publicación; esto podría afectar el resultado de la búsqueda.
Intentaré algo más limpio, como usar una ventana modal y guardar en campos personalizados en su lugar.

EDITAR: Creo que entendí mal :smile: si te refieres a que los cambios aparezcan en el resultado de la búsqueda, la respuesta es no (tampoco aparecerá el HTML).

Esto es genial. Tu video se desplaza rápido. ¿Está la URL en el sitio del foro?

Oye, Dan. ¿Qué quieres decir?

La URL del avatar. ¿Es solo una imagen subida o apunta a un sitio externo?

Esta es una URL externa. Debería ser posible trabajar con una URL local.

Genial, gracias

Pensar que podría ser una buena idea proponer, quizás en la wiki de la comunidad, una guía de plantillas de foros. A menudo, la gente busca ideas sobre diferentes tipos de configuraciones de foros. En este caso, podría ser un poco específico. Pero una plantilla de RPG de mesa que incluya esta característica que creaste.