Sostituzione di avatar e nome utente per un post specifico

Il problema: voglio che gli utenti possano pubblicare come personaggi di gioco di ruolo. Vorrei che potessero inserire un modello in un post, qualcosa come il seguente:

[wrap="characterpost"]
[characterav]https://image.link.example.png[/characterav]
[charactername][[Nome del Personaggio]][/charactername]
[/wrap]

E poi usare uno script in modo che l’immagine sostituisca l’avatar originale e il link al topic del nome del personaggio venga posizionato davanti al nome utente. Ad esempio, se il post dice normalmente “NomeUtente”, vorrei sostituirlo con “Nome del Personaggio interpretato da NomeUtente”.
(“Nome del Personaggio” includerebbe un link a un topic con la scheda del personaggio, sperando di usare semplicemente il componente del tema wikilinks per comodità.)

Ho incollato una struttura di post in un Codepen e sono riuscito a scrivere un po’ di javascript che farebbe esattamente questo. Tuttavia, quando si è trattato di aggiungerlo a un decoratore di post e di farlo funzionare in diretta con l’API, mi sono scontrato con un muro.

Ecco cosa ho in common>header al momento:

<script type="text/discourse-plugin" version="0.8">
api.decorateCookedElement(
  element => {
    
    // trova il tag characterpost all'interno del post
    const characterPost = element.querySelector('[data-wrap="characterpost"]');
	
    // trova il genitore del tag characterpost, che contiene avatar e nome utente
    const characterPostParent = characterPost.closest('article');
	
    // rendilo rosso per vedere se funziona
    characterPostParent.style.backgroundColor = "red";
    
  },
  {
    id: 'render-character-post', onlyStream: true, afterAdopt: true
  }
);
</script>

Questo ha iniziato a generare un errore. È possibile accedere all’involucro “article” per i post usando decorateCookedElement in modo da poter raggiungere il nome utente e l’avatar? Se no, come posso procedere?

Ciao, unfairest,

Mi sono imbattuto in questo post e ho pensato di provarci!

Ecco la prima versione; spero che il codice non sia troppo orribile. :slightly_smiling_face:
Non ho testato a fondo tutti i casi limite. È un punto di partenza.

  • Formato wrap previsto: [wrap=character avatar=\"<URL>\” name=\"<Nome>\"][/wrap]
  • Assicurati che ci sia una riga vuota sotto [wrap]
  • Puoi personalizzare il nome del personaggio con CSS (vedi le classi character e character-extra)

Fammi sapere se riscontri problemi :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;
    }
}

Ecco una piccola demo di come appariva:

Questo è molto bello, grazie per averlo condiviso! Stavo cercando qualcosa di simile anch’io. Sai se questo influisce anche su come i post appaiono nella ricerca?

Ottima domanda! Il nome del tag e il suo contenuto fanno parte del contenuto del post; questo potrebbe influire sui risultati della ricerca.
Proverò qualcosa di più pulito, come usare una modale e salvare nei campi personalizzati invece.

MODIFICA: Penso di aver capito male :smile: se stai parlando di modifiche che appaiono nei risultati della ricerca, la risposta è no (né apparirà l’HTML).

È molto bello. Il tuo video scorre velocemente. L’URL si trova sul sito del forum?

Ehi, Dan. Cosa intendi?

L’URL dell’avatar. È solo un’immagine caricata o punta a un sito esterno?

Questo è un URL esterno. Dovrebbe essere possibile lavorare con un URL locale.

Grazie mille

Potrebbe essere un’idea proporre, magari nella wiki della community, una guida per i template dei forum. Spesso le persone cercano idee per diversi tipi di configurazioni di forum. In questo caso potrebbe essere un po’ di nicchia. Ma un template per GDR da tavolo che includa questa funzionalità che hai creato.