특정 게시물의 아바타와 사용자 이름 변경

문제: 사용자들이 RPG 캐릭터로 게시물을 올릴 수 있도록 하고 싶습니다. 게시물에 아래와 같은 템플릿을 삽입할 수 있도록 하려 합니다:

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

그리고 스크립트를 사용해 이미지가 원래의 아바타를 대체하고, 캐릭터 이름이 주제 링크와 함께 사용자 이름 앞에 표시되도록 하려 합니다. 예를 들어, 게시물이 보통 "Username"이라고 표시된다면, 이를 "Character Name played by Username"으로 대체하고 싶습니다.
("Character Name"은 캐릭터 시트가 있는 주제에 대한 링크를 포함해야 하며, 사용 편의성을 위해 위키링크 테마 구성 요소를 사용하는 것이 좋겠습니다.)

게시물 골격을 Codepen에 붙여넣고, 이 동작을 정확히 수행하는 자바스크립트를 작성하는 데 성공했습니다. 하지만 이를 게시물 데코레이터에 추가하고 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” 래퍼에 접근하여 사용자 이름과 아바타에 도달할 수 있을까요? 불가능하다면, 어떻게 이 문제를 해결할 수 있을까요?

Hi, unfairest,

이 포스트를 우연히 발견해서 한번 시도해 보기로 했어요!

첫 번째 버전입니다. 코드가 너무 엉망이 아니기를 바랍니다. :slightly_smiling_face:
모든 엣지 케이스를 광범위하게 테스트하지는 않았습니다. 시작점일 뿐입니다.

  • 예상되는 래핑 형식: [wrap=character avatar="<URL>" 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: avatar/name sanity check
    
    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로 작업할 수 있어야 합니다.

좋아요, 감사합니다.

커뮤니티 위키에 포럼 템플릿 가이드를 제안하는 것도 좋은 아이디어일 것 같습니다. 다양한 유형의 포럼 설정에 대한 아이디어를 찾는 분들이 많으니까요.

이 경우엔 다소 틈새 분야일 수 있겠지만, 당신이 만든 이 기능을 포함하는 테이블톱 RPG 템플릿을 만들어 보는 건 어떨까요?