Codex에서 AI(GPT 5.6 Sol Ultra) 진단 (참고 사항):
원인을 찾았습니다: Discourse Reactions 플러그인이 전역적인 “텍스트 선택 금지” 상태를 누출시키고 있습니다.
- 반응(reaction) 버튼의
touchstart이벤트가plugins/discourse-reactions/assets/javascripts/discourse/components/discourse-reactions-actions.gjs:222에서<html>태그에discourse-reactions-no-select클래스를 추가합니다. - 해당 클래스는
plugins/discourse-reactions/assets/stylesheets/common/discourse-reactions.scss:1에서 문서 전체에user-select: none을 적용하고 WebKit의 롱터치 콜아웃(long-touch callout)을 비활성화합니다. - 반응 버튼 위에서 세로 스크롤이 시작되면,
plugins/discourse-reactions/assets/javascripts/discourse/components/discourse-reactions-actions.gjs:249에서 제스처를 무효(invalid)로 처리하지만 클래스는 제거하지 않습니다. - 이후
plugins/discourse-reactions/assets/javascripts/discourse/components/discourse-reactions-actions.gjs:257에서 조기 반환(early return)이 발생하여 클래스가 영원히 남아 있게 됩니다. - 또한
touchcancel이벤트나 컴포넌트 파괴 시의 클린업(cleanup) 로직도 존재하지 않습니다.
클래스가 제거되는 유일한 위치는 plugins/discourse-reactions/assets/javascripts/discourse/components/discourse-reactions-actions.gjs:690입니다. 이는 보고된 우회 방법(The popup menu for quoting text is unresponsive on Android)을 설명합니다: 반응 팝업을 열었다가 닫으면 collapseAllPanels()가 호출되어 텍스트 선택이 복구됩니다.
인용(quote) 툴바 자체는 하류(downstream)에 위치합니다. frontend/discourse/app/components/post-text-selection.gjs:58에서 selectionchange 이벤트를 듣고 실제 브라우저 선택 상태를 요구합니다. 전역 user-select: none이 적용된 상태에서는 Android에서 해당 선택이 생성되지 않습니다.
히스토리는 이 버그 계열을 확인해 줍니다: 2023년 스크롤 수정(FIX: prevents triggering a reaction while scrolling (#224) · discourse/discourse-reactions@d1970cf · GitHub)에서 무효 터치 시 조기 반환이 도입되었고, 2024년 부분 수정(FIX: couldn't select text after dismissing a reaction (#296) · discourse/discourse-reactions@c6710ef · GitHub)에서 클린업을 패널 접힘 시점으로 옮겼지만 스크롤/취소 경로는 여전히 미처리 상태였습니다.
요약하자면, 문제는 다음 요소들의 조합입니다:
-
touchStart가 전역discourse-reactions-no-select클래스를 추가합니다. -
touchMove가 스크롤 제스처를 무효로 표시하지만 이를 해제하지 않습니다. -
touchEnd가 무효 제스처를 감지하고 조기 반환합니다. -
팝업이 열리지 않았으므로
collapseAllPanels()가 클래스를 해제하지 않습니다.
그 결과 페이지 전체에 user-select: none이 유지됩니다. touchcancel도 미처리 경로이지만, vertical-scroll 경로가 주된 핵심 문제입니다.
수정 방법은 완료, 거부, 취소 또는 파괴된 모든 터치 라이프사이클에서 클래스를 해제하는 것이며, touchstart → touchmove → touchend 및 touchcancel 시나리오에 대한 회귀 테스트(regression tests)를 포함해야 합니다.