特定の投稿のアバターとユーザー名を変更する

問題点:ユーザーがRPGキャラクターとして投稿できるようにしたいです。投稿内にテンプレート挿入機能を設けたいと考えています。例えば、以下のようなもの:

[wrap="characterpost"]
[characterav]https://image.link.example.png[/characterav]
[charactername][[Character Name]][/charactername]
[/wrap]
```\n
そして、スクリプトを使って、画像が元のアバターに置き換えられ、キャラクター名のトピックリンクがユーザー名の前に表示されるようにします。例えば、通常投稿に「Username」と表示されている場合、それを「Character Name played by Username」に置き換えたいです。
(「Character Name」には、キャラクターのシートを扱うトピックへのリンクを含め、使いやすさのために wikilinks テーマコンポーネントを使用できれば理想的です。)

投稿の骨格を Codepen に貼り付け、これを正確に実現する JavaScript を書くことができました。しかし、これを投稿デコレーターに組み込み、API とライブで動作させる段階で壁にぶつかりました。

現在、common>header には以下を配置しています:

```js
<script type="text/discourse-plugin" version="0.8">
api.decorateCookedElement(
  element => {
    
    // 投稿内の characterpost タグを見つける
    const characterPost = element.querySelector('[data-wrap="characterpost"]');
	
    // characterpost タグの親要素(アバターとユーザー名を含むもの)を見つける
    const characterPostParent = characterPost.closest('article');
	
    // 動作確認のため、赤くする
    characterPostParent.style.backgroundColor = "red";
    
  },
  {
    id: 'render-character-post', onlyStream: true, afterAdopt: true
  }
);
</script>

これによってエラーが発生しています。decorateCookedElement を使用して投稿の「article」ラッパーにアクセスし、ユーザー名とアバターを取得することは可能でしょうか?もし不可能な場合、どのように進めればよいでしょうか?

こんにちは、unfairestさん

この投稿を見つけて、試してみようと思いました!

最初のバージョンです。コードがあまりひどくないことを願っています。:slightly_smiling_face:
すべてのエッジケースを広範囲にテストしたわけではありません。これは出発点です。

  • 期待されるラップ形式: [wrap=character avatar=\"<URL>\” name=\"<Name>\"][/wrap]
  • [wrap] の下に空行があることを確認してください。
  • CSS でキャラクター名をカスタマイズできます (character および character-extra クラスを参照)。

何か問題があればお知らせください :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;
    }
}

これはどのように見えるかの簡単なデモです:

これは素晴らしいですね、共有していただきありがとうございます!私も同様のものを探していました。これは検索での投稿の表示にも影響しますか?

良い質問ですね!タグ名とその内容は投稿コンテンツの一部であり、検索結果に影響を与える可能性があります。
モーダルを使用してカスタムフィールドに保存するなど、よりクリーンな方法を試してみます。

編集:誤解していたようです :smile: 検索結果に表示される変更について話しているのであれば、答えはノーです(HTMLも表示されません)。

これはかなりクールですね。動画が速くスクロールします。URLはフォーラムサイトにありますか?

ねえ、ダン。どういう意味?

アバターのURLは、アップロードされた画像ですか、それとも外部サイトを指していますか?

これは外部URLです。ローカルURLでも機能するはずです。

クール、ありがとう

コミュニティWikiでフォーラムテンプレートガイドを提案するのは良いかもしれません。フォーラムのセットアップの種類に関するアイデアを探している人がよくいるからです。

この場合は少しニッチかもしれませんが、あなたが作成したこの機能を含むテーブルトップRPGテンプレートはどうでしょうか。