Avatar und Benutzername für einen bestimmten Beitrag ändern

Das Problem: Ich möchte, dass Benutzer als RPG-Charaktere posten können. Ich würde gerne, dass sie eine Vorlage in einen Beitrag einfügen können – etwas wie Folgendes:

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

Und dann ein Skript verwenden, damit das Bild den ursprünglichen Avatar ersetzt und der Themenlink für den Charakternamen vor den Benutzernamen gesetzt wird. Zum Beispiel, wenn der Beitrag normalerweise „Benutzername“ anzeigt, möchte ich das durch „Charaktername gespielt von Benutzername“ ersetzen.
(„Charaktername“ würde einen Link zu einem Thema mit dem Charakterbogen enthalten, hoffentlich einfach nur mit dem Wikilinks-Theme-Component, um die Nutzung zu vereinfachen.)

Ich habe ein Beitragsgerüst in einen Codepen eingefügt und konnte etwas JavaScript schreiben, das genau das tut. Allerdings bin ich auf eine Mauer gestoßen, als es darum ging, es in einen Post-Decorator zu integrieren und mit der API live zum Laufen zu bringen.

Das habe ich gerade in common>header:

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

Dieser Code hat einen Fehler verursacht. Ist es möglich, auf die „article“-Hülle für Beiträge mit decorateCookedElement zuzugreifen, damit ich auf den Benutzernamen und den Avatar zugreifen kann? Wenn nicht, wie kann ich das angehen?

Hallo, unfairest,

Ich bin auf diesen Beitrag gestoßen und dachte, ich könnte ihn ausprobieren!

Hier ist die erste Version; ich hoffe, der Code ist nicht allzu schrecklich. :slightly_smiling_face:
Ich habe nicht alle Randfälle ausgiebig getestet. Es ist ein Ausgangspunkt.

  • Erwartetes Wrap-Format: [wrap=character avatar=\"<URL>\"]<Name>[/wrap]
  • Stellen Sie sicher, dass sich unter [wrap] eine Leerzeile befindet
  • Sie können den Charakternamen mit CSS anpassen (siehe Klassen character und character-extra)

Lassen Sie mich wissen, wenn Sie Probleme haben :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', 'gespielt von'), // 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;
    }
}

Hier ist eine kleine Demo, wie es aussah:

Das ist sehr cool, danke fürs Teilen! Ich habe auch nach etwas Ähnlichem gesucht. Weißt du, ob sich das auch darauf auswirkt, wie Beiträge in der Suche erscheinen?

Gute Frage! Der Tag-Name und sein Inhalt sind Teil des Beitragsinhalts; dies könnte das Suchergebnis beeinflussen.
Ich werde etwas Saubereres versuchen, wie die Verwendung eines Modals und das Speichern in benutzerdefinierten Feldern anstelle dessen.

EDIT: Ich glaube, ich habe das missverstanden :smile: Wenn Sie von Änderungen sprechen, die im Suchergebnis erscheinen, lautet die Antwort nein (noch wird das HTML erscheinen).

Das ist ziemlich cool. Dein Video scrollt schnell. Ist die URL auf der Forum-Seite?

Hallo Dan. Was meinst du?

Die Avatar-URL. Ist das nur ein hochgeladenes Bild oder verweist es auf eine externe Website?

Dies ist eine externe URL. Es sollte möglich sein, mit einer lokalen URL zu arbeiten.

Danke, cool

Es könnte eine Idee sein, im Community-Wiki einen Leitfaden für Forenvorlagen vorzuschlagen. Da die Leute oft nach Ideen für verschiedene Arten von Foreneinrichtungen suchen. In diesem Fall könnte es etwas speziell sein. Aber eine Tabletop-RPG-Vorlage, die dieses von Ihnen erstellte Feature enthält.