Sostituire avatar e username per un post specifico

Il problema: Voglio che gli utenti possano pubblicare come personaggi di GDR. Vorrei che potessero inserire un modello in un post, qualcosa di simile a quanto segue:

[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 all’argomento charactername vada davanti al nome utente. Ad esempio, se il post dice normalmente “Nome utente”, voglio sostituirlo con “Nome del Personaggio interpretato da Nome utente”.
(“Nome del Personaggio” includerebbe un link a un argomento con la scheda del personaggio, sperando di utilizzare solo il componente tematico wikilinks per facilità d’uso.)

Ho incollato uno scheletro di post in un Codepen e sono stato in grado di scrivere del javascript che farebbe esattamente questo. Tuttavia, quando si è trattato di aggiungerlo a un decoratore di post e farlo funzionare in tempo reale con l’API, mi sono imbattuto in un muro.

Ecco quello che ho in common>header in questo 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 generato un errore. È possibile accedere all’involucro “article” per i post utilizzando decorateCookedElement in modo da poter accedere al nome utente e all’avatar? In caso contrario, come posso procedere?

4 Mi Piace

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:

7 Mi Piace

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).

2 Mi Piace

È 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.

2 Mi Piace

Grazie mille

1 Mi Piace

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.