Remplacement de l'avatar et du nom d'utilisateur pour un message spécifique

Le problème : Je veux que les utilisateurs puissent poster en tant que personnages de RPG. Je voudrais qu’ils puissent insérer un modèle dans un message - quelque chose comme ceci :

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

Et ensuite utiliser un script pour que l’image remplace l’avatar d’origine et que le lien du sujet charactername apparaisse devant le nom d’utilisateur. Par exemple, si le message dit normalement “Username”, je veux le remplacer par “Character Name joué par Username”.
( “Character Name” inclurait un lien vers un sujet avec la fiche du personnage, en espérant utiliser simplement le composant thématique wikilinks pour plus de facilité.)

J’ai collé un squelette de message dans un Codepen et j’ai pu écrire un script javascript qui ferait exactement cela. Cependant, lorsque j’ai voulu l’ajouter à un décorateur de message et le faire fonctionner en direct avec l’API, j’ai rencontré un obstacle.

Voici ce que j’ai dans le common>header en ce moment :

<script type="text/discourse-plugin" version="0.8">
api.decorateCookedElement(
  element => {
    
    // trouver la balise characterpost dans le message
    const characterPost = element.querySelector('[data-wrap="characterpost"]');
	
    // trouver le parent de la balise characterpost, qui contient l'avatar et le nom d'utilisateur
    const characterPostParent = characterPost.closest('article');
	
    // le rendre rouge pour voir si ça fonctionne
    characterPostParent.style.backgroundColor = "red";
    
  },
  {
    id: 'render-character-post', onlyStream: true, afterAdopt: true
  }
);
</script>

Cela a généré une erreur. Est-il possible d’accéder à l’enveloppe “article” des messages avec decorateCookedElement afin de pouvoir accéder au nom d’utilisateur et à l’avatar ? Sinon, comment puis-je procéder ?

4 « J'aime »

Salut, unfairest,

Je suis tombé sur ce post et j’ai pensé que je pourrais essayer !

Voici la première version ; j’espère que le code n’est pas trop horrible. :slightly_smiling_face:
Je n’ai pas testé de manière exhaustive tous les cas limites. C’est un point de départ.

  • Format d’enroulement attendu : [wrap=character avatar=\"<URL>\"]<Nom>[/wrap]
  • Assurez-vous qu’il y a une ligne vide sous [wrap]
  • Vous pouvez personnaliser le nom du personnage avec CSS (voir les classes character et character-extra)

Faites-moi savoir si vous rencontrez des problèmes :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;
    }
}

Voici une petite démo de ce à quoi cela ressemblait :

7 « J'aime »

C’est très cool, merci de partager ! Je cherchais aussi quelque chose de similaire. Savez-vous si cela affecte également la façon dont les publications apparaissent dans les résultats de recherche ?

Bonne question ! Le nom de la balise et son contenu font partie du contenu du message ; cela pourrait affecter le résultat de la recherche.
Je vais essayer quelque chose de plus propre, comme utiliser une modale et enregistrer dans des champs personnalisés à la place.

EDIT : Je pense que j’ai mal compris :smile : si vous parlez des changements apparaissant dans le résultat de la recherche, la réponse est non (ni le HTML n’apparaîtra).

2 « J'aime »

C’est plutôt cool. Votre vidéo défile rapidement. L’URL se trouve-t-elle sur le site du forum ?

Salut Dan. Qu’est-ce que tu veux dire ?

L’URL de l’avatar. S’agit-il simplement d’une image téléchargée ou d’un lien vers un site externe ?

Ceci est une URL externe. Il devrait être possible de travailler avec une URL locale.

2 « J'aime »

Cool merci

1 « J'aime »

Il pourrait être judicieux de proposer, peut-être dans le wiki communautaire, un guide de modèles de forum. Souvent, les gens viennent chercher des idées sur différents types de configurations de forum. Dans ce cas, cela pourrait être un peu spécifique. Mais un modèle de jeu de rôle sur table qui inclut cette fonctionnalité que vous avez créée.