特定の投稿のためにアバターとユーザー名を置き換える

問題:ユーザーがRPGキャラクターとして投稿できるようにしたい。投稿に以下のようなテンプレートを挿入できるようにしたい。

[wrap="characterpost"]
[characterav]https://image.link.example.png[/characterav]
[charactername][[キャラクター名]][/charactername]
[/wrap]

そして、スクリプトを使用して、画像が元のプロフィール画像に置き換わり、characternameのトピックリンクがユーザー名の前に表示されるようにしたい。例えば、投稿が通常「ユーザー名」と表示される場合、「キャラクター名(ユーザー名がプレイ)」のように置き換えたい。
(「キャラクター名」には、キャラクターシートへのリンクが含まれる予定で、使いやすさのためにウィキリンクテーマコンポーネントを使用する予定です。)

投稿のスケルトンをCodepenに貼り付け、これを実現できるJavaScriptを記述することができた。しかし、投稿デコレーターに追加してAPIでライブで動作させようとしたところ、行き詰まってしまった。

現在、common>headerにあるのは以下の通り。

<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」ラッパーにアクセスし、ユーザー名とアバターに到達することは可能か?もし不可能なら、どのように進めればよいか?

「いいね!」 4

こんにちは、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;
    }
}

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

「いいね!」 7

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

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

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

「いいね!」 2

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

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

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

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

「いいね!」 2

クール、ありがとう

「いいね!」 1

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

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