모바일 최신 탭에서 주제 꾸미기

사용자 정의 사용자 필드에 포함된 키워드가 있는 게시글을 차단하는 테마 컴포넌트를 개발 중입니다. 데스크톱 뷰에서 최신 또는 인기 목록에 표시될 때 답글과 주제(topic)를 모두 숨기는 기능은 정상적으로 작동합니다. 하지만 앱이나 모바일에서 보게 되면 주제가 차단되었다는 알림은 추가되지만, 콘텐츠에는 차단 클래스가 적용되지 않습니다. 주제 안의 답글을 차단하는 기능은 모바일이나 앱에서 모두 정상적으로 작동합니다.

components를 살펴봤는데 모바일용으로는 별도의 .hbs가 사용되지 않는 것으로 보이는데, 제가 놓치고 있는 다른 부분이 있을까요?

const discourseComputed = require("discourse-common/utils/decorators").default;

function addIgnoredTopicClass() {
    if (currentUser) {
        api.container.lookup('store:main').find('user', currentUser.username).then((user) => {
            const blocklist = user.user_fields[1];
            const case_sensitive = user.user_fields[2];
            const whole_words = user.user_fields[3];
    
            const blocked = blocklist.split(",").map(function(item) {
                if (case_sensitive) {
                    return item.trim();
                } else {
                    return item.trim().toLowerCase();
                }
            });
            let classList = this._super(...arguments);
            let elem = document.querySelectorAll("[data-topic-id='" + this.topic.id.toString() + "']")[0];
            console.log(elem);
            const title = (case_sensitive) ? this.topic.fancy_title : this.topic.fancy_title.toLowerCase();
            const excerpt = (case_sensitive) ? this.topic.excerpt : this.topic.excerpt.toLowerCase();
            let result = "";
            
            for (let index = 0; index < blocked.length; ++index) {
                    let pattern = (whole_words) ? new RegExp('(?:\\b|\\s|^)' + blocked[index] + '(?:\\b|\\s|$)') : new RegExp(blocked[index]);
                    // console.log(pattern)
                    if (pattern.test(title)) {
                        classList += "blocker-blocked"
                        const found = blocked.filter(text => title.includes(text));
                        if (found.length >= 2) {
                            const last = found.pop();
                            result = found.join(', ') + ' and ' + last;
                        } else {
                            result = found.join(', ');
                        }
                        const newNode = document.createElement("a");
                        const textNode = document.createTextNode("Blocked for containing " + result + ".");
                        newNode.classList.add("block-notice")
                        newNode.appendChild(textNode);
                        newNode.onclick = function() { showComment(this); };
                        elem.children[0].insertBefore(newNode, elem.children[0].children[0]);
                        for (let index = 0; index < elem.children.length; ++index) {
                            if (elem.children[index].classList.contains('main-link')) {
                                elem.children[index].classList.add("blocker-blocked");
                            }
                        }
                        newNode.classList.remove("blocker-blocked");
                    }
                }
            
            // console.log(classList);
            return classList;
        });
    }
}

api.modifyClass("component:topic-list-item", {
    @discourseComputed()
    unboundClassNames() {
        return addIgnoredTopicClass.call(this);
    }
});
    
api.modifyClass("component:latest-topic-list-item", {
    
    @discourseComputed()
    unboundClassNames() {
        return addIgnoredTopicClass.call(this);
    }
});

아니면, 적어도 나는 이게 제대로 작동한다고 생각했어요. 잠시 다른 작업에 집중하다가 다시 돌아왔더니 이제 안 되는 것 같아요 :thinking: 아마 이 api.modifyClass 문제 때문일까요?

궁금해서 묻는데, 이 기능은 내장된 감시 단어 기능과 어떻게 다른가요?

제 이해가 맞다면, Watched Words는 모든 사용자에게 적용되는 관리자 설정이 맞죠? 제가 하려는 것은 사용자가 각자 자신의 watched words 필터를 설정할 수 있게 하여, 포럼 규칙상 문제는 없지만 개인적인 이유로 보고 싶지 않은 게시글을 차단할 수 있게 하는 것입니다.

가상의 시나리오를 들어볼게요: 반려동물 포럼에 반려동물 털 관리에 대한 일반 스레드가 있다고 가정해 봅시다. 이 스레드의 주요 주제는 특정 동물 종류로 태그가 지정되어 있지 않습니다. 사용자 A는 자신의 개에 대해 답글을 달고, 사용자 B는 자신의 고양이에 대해 답글을 달지만, 사용자 A는 고양이와 관련된 내용은 전혀 보고 싶지 않습니다. 이 테마 컴포넌트는 사용자 A가 자신의 차단 목록에 "cat"을 입력할 수 있게 하고, 그러면 주제나 답글 어디에 "cat"이든 "고양이가 포함되어 있어 차단됨"으로 대체되고, 클릭하면 그래도 표시되도록 하는 것입니다.

이것은 포럼의 일반적인 규칙에 부합하고 주제와 관련된 내용이지만, 태그가 지정되지 않았거나 사용자 A가 보고 싶은 내용으로 태그된 스레드의 답글에서 언급될 수 있는 것을 위한 것입니다. 제가 이전으로 이전하던 포럼에서는 페이지가 로드된 후 페이지를 스캔하는 작은 브라우저 사용자 스크립트를 사용했는데, Discourse의 매력 중 하나는 모바일에서도 작동할 수 있도록 차단 기능을 내장할 수 있다는 점입니다(사용하던 사용자 스크립트는 모바일 브라우저에서 실행되지 않음). 사용자가 규칙 위반 없이 X를 보고 싶지 않다고 결정할 수 있다면 일반 스레드에 무엇이 속하는지에 대한 플래깅과 논쟁을 줄일 수 있습니다.

이것을 정식 테마 컴포넌트로 게시하지는 않을 것 같습니다. 관리자 패널에서 세 개의 사용자 필드를 생성해야 하기 때문입니다(이것은 자동으로 생성하려면 플러그인이 필요할 것 같다고 생각합니다). 저는 여기서 기본 호스팅 플랜을 사용 중이므로 플러그인으로 возиться하지는 않지만, 완료되면 완성된 테마 컴포넌트 코드와 사용자 필드 설정을 게시할 수 있습니다.

정말 멋진 아이디어네요. :slight_smile: 이 기능이 유용할 포럼이 몇 군데 떠오릅니다.

네, 가능성이 있어 보입니다. 심지어 수정된 버전을 사용해 사용자 차단 기능을 확장할 수도 있겠네요. 제가 특정 사용자 한 명에게서 불평을 받고 있는데 :man_facepalming: 차단한 사람의 답변을 여전히 볼 수 있다는 거예요. ㅋㅋ

흥미로운 가능성이 많네요. 프로젝트 계속 지켜볼게요.
:vulcan_salute::smiling_face_with_sunglasses::+1:

문제가 어디에서 발생하는지 파악하는 방법을 알고 싶습니다. Chrome 개발자 도구의 모바일 모드를 사용하면 정상적으로 작동하지만, 실제 스마트폰의 Chrome이나 Android 앱에서는 작동하지 않습니다. Plugin Outlets 테마 컴포넌트를 사용해도, topic-list-item 내부에서 수정하려고 하고 있기 때문에 관련 아웃렛이 보이지 않습니다.

기본적인 질문일 수 있어 죄송합니다. 저는 Ember를 처음 사용해 봅니다.

모바일에서 동작하도록 만들었고, 승인되면 Customization > Theme component 채널에 게시할 예정입니다. 모바일에서 발생한 문제는 ‘main-link’ 클래스가 있는 topic-list의 자식 요소에 클래스를 추가했는데, 모바일에서는 데스크톱과 달리 해당 main-link 자식 요소가 계층 구조에서 몇 단계 더 아래에 위치해 있었기 때문입니다.