컴포저에 외부 위젯 추가하기

컴포저에 위젯을 추가하려고 합니다. 툴바에서 코드를 삽입하는 것까지는 성공했지만, 그 안에서 JavaScript가 작동하도록 하는 방법을 모르겠습니다. 외부 사이트에서 불러오는 대신 플러그인이나 테마 컴포넌트 형태로 내부에 JavaScript를 추가해야 할 것 같은데, 어떻게 진행해야 할지 모르겠습니다. 컴포저 안에서 이 작업이 가능한가요?

무엇을 하려는 건지 조금 더 구체적으로 설명해 주시겠어요? 새 툴바 버튼을 추가해서 작성 영역(textarea)에 콘텐츠를 넣는 건가요? 아니면 다른 건가요?

제가 시도하는 것은 사용자가 컴포저에서 특정 위젯을 삽입할 수 있도록 하는 것입니다. 사용자가 숫자만 입력하면 툴바가 해당 숫자를 감싸는 형태로 동작해야 합니다. 예를 들어 112756을 입력하면 다음과 같은 코드가 그 숫자를 감싸서 생성됩니다.

<div id='PurpleAirWidget_112756_module_AQI_conversion_C0_average_10_layer_detailed'>Loading PurpleAir Widget...</div>
<script src='https://www.purpleair.com/pa.widget.js?key=N6HB6JJ0BP1Z05SE&module=AQI&conversion=C0&average=10&layer=detailed&container=PurpleAirWidget_112756_module_AQI_conversion_C0_average_10_layer_detailed'></script>

결과는 다음과 같이 보이면 좋겠습니다.

네, 그러면 이미 컴포저에 콘텐츠를 추가하는 방법을 알아낸 것 같습니다? (아니라면 이 예시를 참고해 보세요: GitHub - discourse/discourse-gifs · GitHub - 이 테마 컴포넌트는 툴바에서 버튼을 클릭할 때 모달을 열고, 모달에서 콘텐츠를 클릭하면 컴포저에 콘텐츠를 삽입합니다.)

스크립트를 로드하여 게시글 콘텐츠에 무언가를 적용하려는 것이라면, 이 게시글이 올바른 방향으로 이끌어 줄 수 있을 것 같습니다… loadScript와 decorateCooked를 사용하는 방법입니다: Difficulties in correctly adding external JavaScript - #4 by StevenTammen

이것을 어떤 방식으로든(직접 사용하거나 포크하여 커스터마이징하여) 활용할 수 있을 것입니다: Mentionables 이 링크는 컴포저 버튼 대신 특수 문자를 사용합니다.

방향을 잡아주셔서 감사합니다. 그런데 또 다른 문제가 생겼습니다. 해당 스크립트를 사용하는 토픽 페이지를 열 때 로딩/렌더링이 되지 않아요. 페이지를 새로고침해야 제대로 로딩되는데, 그것도 매번은 아닙니다. 이 문제가 Discourse가 단일 페이지 애플리케이션(SPA)이기 때문인가요? 제 Discourse 지식이 부족한 건지, 아니면 제가 직접 프로그래밍해야 하는 부분인지 파악하려고 합니다.

현재 사용하고 있는 코드는 다음과 같습니다. 어떤 방향의 조언이라도 감사히 듣겠습니다.

 let loadScript = require('discourse/lib/load-script').default;
  api.decorateCooked($elem => { $elem.children('div[data-PAWidget]').ready(function() {
         $elem.children('div[data-PAWidget]').append(" <div id='PurpleAirWidget_11726_module_AQI_conversion_C0_average_0_layer_standard'>Loading PurpleAir Widget...</div>");
       loadScript("https://www.purpleair.com/pa.widget.js?key=21R72LUN79CXRZ50&module=AQI&conversion=C0&average=0&layer=standard&container=PurpleAirWidget_11726_module_AQI_conversion_C0_average_0_layer_standard").then(()=>{       
    })  
  })     
  });

이 문제를 시도해 봤는데 비슷한 결과를 얻었습니다. decorateCooked는 결국 비추천(deprecate)될 예정이라 decorateCookedElement를 사용하려고 했습니다.

 api.decorateCookedElement(
    (element) => {
      element.childNodes.forEach((node) => {
        if (node.dataset && node.dataset.pawidget) {
          node.insertAdjacentHTML(
            "beforeend",
            "<div id='PurpleAirWidget_11726_module_AQI_conversion_C0_average_0_layer_standard'>Loading PurpleAir Widget...</div>"
          );

          loadScript(
            `https://www.purpleair.com/pa.widget.js?key=${node.dataset.pawidget}&module=AQI&conversion=C0&average=0&layer=standard&container=PurpleAirWidget_11726_module_AQI_conversion_C0_average_0_layer_standard`
          );
        }
      });
    },
    { id: "widget-append", onlyStream: true, afterAdopt: true }
  );

여기서 약간의 차이는 키를 data 속성으로 전달했다는 점입니다:

<div data-PAWidget="21R72LUN79CXRZ50"></div>

스크립트가 처음 로드된 경우라면 제 환경에서는 잘 작동합니다. 하지만 스크립트가 포함된 게시물을 보고 나서 주제 목록으로 돌아가 다시 해당 주제에 진입하면 작동하지 않습니다(새로고침을 해야만 작동합니다). 관련 게시물이 로드될 때마다 decorateCookedElement가 발동되는 것을 확인할 수 있지만, 스크립트가 다시 작동하지 못하게 막는 무언가가 있는 것 같습니다.

관련이 있을지 확실하지는 않지만, pa.widget.js에서 콘솔에 Uncaught TypeError: i is null 오류도 보입니다:

Screen Shot 2021-11-08 at 9.11.39 PM

도전해 주셔서 감사합니다. 페이지를 열어 둔 채로 두면 대략 90초에서 2분 사이에 스크립트가 호출되는 것을 확인했습니다.

결국 로딩은 되네요. 나중에 로딩되는 이유나 방식에 대한 문서나 게시물이 있을까요?