본문 바로가기
Web Development/Mediawiki

[Mediawiki] 미디어 위키에서 조건 별, 문서 통합 조회 기능 만들기(feat. DynamicPageList3 Extension, MediaWiki API)

by 감자맹고우 2022. 8. 9.
728x90
반응형

미디어위키를 사용하다보니 생각보다 이용에 불편함이 많다.

그러다보니 이미 그런 불편함을 겪은 사람들이, Extension으로 많은 기능을 구현해 놓았음을 알 수 있었다.

덕분에 Extension을 설정해주는 것만으로 요청을 쳐낼 수 있었는데, 이번에 들어온 요청에 대해서는 결과가 조금 달랐다.

프로젝트에서 요청된 기능은 진행 현황을 확인할 수 있는 일종의 통합문서였는데, 예를 들면 이런 기능이다.

 

< 예시 >
- 카테고리 : 산림현황
- 상태 : 1월 서울숲 산림 조성 현황 ~ 12월 서울숲 산림 조성 현황까지 따로 문서가 있음
- 구현해야 할 기능 : '서울숲 산림 현황' 이라는 문서를 통해 1 ~ 12월 문서의 제목과 특정 일부 내용까지 미리보기식으로 조회할 수 있어야 한다.

 

즉, 표로 1 ~ 12월의 다른 문서의 제목과 내용 일부를 받아올 수 있어야 했는데,

아무리 뒤져봐도 해당 기능을 제공하는 Extension은 존재하지 않았다.

애초에, 위키는 나무위키 만 보아도 알 수 있듯 링크를 타고 타고 들어가도록 사용하는 형식이라서,

제목과 URL은 Extension이 없이도 받아오지만, 다른 문서의 내용을 직접 가져오지는 않는다.

 

그렇기 때문에 구글링을 열심히 해보았지만 질문도, 답변도, Extension도 발견할 수 없었다. 그나마 관련된 내용이라면 DynamicPageList3 라는 Extension이 있어서 다른 문서의 정보를 조금 더 받아올 수 있다는 것은 확인할 수 있었지만 내용은 제공되지 않았다.

 

 

DPL3 기능을 테스트해보면서, 요즘 한창 생각에 빠져있던 API가 문득 떠올랐고, 위키도 DB와 통신하는 API가 구현되어 있지 않을까 찾아본 결과, 있음을 확인했다. 그래서 DPL3, Wiki API, 위키의 Common.js 를 통해 해당 기능을 구현하였다.

물론, 이 글의 코드는 우리 프로젝트에 특화된 것이겠지만, 이 방식을 통해 다음 사용자들이 미디어 위키에서 추가 기능을  얼마든지 구현할 수 있을 것이라 생각한다. 그렇기에 이를 공유하고자 한다.

 

 

[ 구현 방법 ]

 

1. DPL3(DynamicPageList3) Extension을 통해, 검색 조건에 따른 문서 리스트를 출력한다.

 

DPL3 설치.

설치 후 조회할 문서에서 원본 편집을 눌러 다음을 작성한다.

 

<dpl>
  category=산림현황
  titlematch=%월%
  headermode=definition
  mode=unordered
  listattr= class="menu-list"
</dpl>

 

간단히 설명하면, dpl 양식은 위와 같이 작성한다.

이 때 dpl의 속성으로 여러가지를 적을 수 있는데 작성은 dpl태그 사이에 각 속성을 한 줄에 한 개씩 적으면 된다.

여기서는 5가지의 속성을 사용하였다.

 

- category : 검색할 문서의 category → (분류:산림현황)
- titlematch : 검색할 문서의 제목 조건 → (제목에 '월'이 들어가는 경우로 조건을 설정하였음)
- headermode : 헤더 모드 → (definition : dl 태그 처리, 잘못 사용한 것 같기도...)
- mode : output format 모드 → (unordered : ul 태그 처리)
- listattr : 속성 부여 → (js, css 처리를 위해 클래스 속성 부여)

 

자세한 사항은 아래의 공식 사이트를 참고하면 좋다.

 

 

DPL3/Parameters: Controlling output format

You can select one of several default formats or define your own format (mode=userformat); output can be grouped in columns or rows.

help.fandom.com

 

반응형

 

2. Javascript (Mediawiki:Common.js) 를 통해 CreateElement로 출력 설정해준다.

3. Wiki API를 통해 정보를 받아와 생성된 Element에 삽입 및 Element를 생성해준다.

 

/** Mediawiki:Common.js **/

// dpl3 로 생성한 ul 태그를, 부여하였던 클래스 속성으로 조회하여 변수로 할당
var categories = document.querySelector(".menu-list");

if(categories != null) {
    var table = document.createElement( 'table' );
    
    // TH 설정 (TITLE)
    var tr = document.createElement( 'tr' );

    var th1 = document.createElement( 'th' );
    th1.innerText = '문서 제목';
    tr.appendChild( th1 );

    var th2 = document.createElement( 'th' );
    th2.innerText = '문서 내용';
    tr.appendChild( th2 );

    table.appendChild( tr );


    // TD 설정 (CONTENT)
    // ul에서 li 갯수만큼 행을 생성
    for(var i = 0; i < categories.childNodes.length; i++) {
      var row = document.createElement( 'tr' );
      var column1 = document.createElement( 'td' );
      
      // 1. 제목은 위키 기본 기능처럼 a태그를 이용해 URL 연결
      var link = document.createElement( 'a' );
      link.setAttribute('href', categories.childNodes[i].childNodes[0].getAttribute('href'));
      link.innerText = categories.childNodes[i].innerText;
      link.setAttribute('style', 'color: #0645AD; font-weight: bold;');
      column1.appendChild( link );
      
      row.appendChild( column1 );

      // 2. 다른 문서의 정보 중 마지막 문단(section)의 index값 조회
      // = 프로젝트에서 마지막 문단의 내용을 받아오면 되었기에 이 부분은 상황에 맞게 변경할 것
      var endNum;
      $.ajax({
        type: "POST",
        url: mw.util.wikiScript('api'),
        data: {action: 'parse', format: 'json', page: link.innerText},
        dataType: 'json',
        async: false,
        success: function ( result ){
          //마지막 문단 index값 저장
          endNum = result.parse.sections.length;
        }
      });


      // 3. 마지막 문단 정보 조회
      // = 프로젝트에서 마지막 문단의 내용을 받아오면 되었기에 이 부분은 상황에 맞게 변경할 것
      var text, textArr;
      var text1 = '';  //출력할 값을 저장할 변수

      $.ajax({
        type: "POST",
        url: mw.util.wikiScript('api'),
        data: {action: 'parse', format: 'json', page: link.innerText, prop: 'wikitext', section: endNum},
        dataType: 'json',
        async: false,
        success: function ( result ){
          textObj = result.parse.wikitext;
          text = JSON.stringify(textObj);  // *이라는 key값으로 value가 조회되어 string으로 변환하여 처리

          textArr = text.split('|}');
          //구분자를 '|}' 로 설정하여 문자열 자르기 (구분자는 상황에 맞게 설정)
          //필자는 가져올 문서 내에 위키의 transclusion 기능을 이용해 구분자를 따로 설정해주었음
          
          // (예시)
          // "*" : "{1월| 1월 수목 증가 수 : 1279 |}"
          // 이 값을 구분자 |와 |} 를 통해 "1월 수목 증가 수 : 1279"만 가져오도록 함
        }
      });
      
      for(var j = 0; j < textArr.length; j++) {
        //잘라진 문자열 배열에서 각 문자열을 추가로 잘라주었음
        
        //lastIndexOf를 통해 마지막부터 조회하여 처음 만나는 |를 찾고, | 다음 문자 index를 저장
        //(구분자는 상황에 맞게 설정)
        var indexNum = textArr[j].lastIndexOf('|') + 1;
        //저장한 index부터 마지막 문자까지의 문자열을 저장
        var temp = textArr[j].substr(indexNum);
        
        //저장한 문자열을 출력할 변수에 저장(이 부분은 상황에 맞게 변경)
        text1 = temp;
      }

      var column2 = document.createElement( 'td' );
      column2.innerText = text1;
      row.appendChild( column2 );

      table.appendChild( row );
    }

    // 생성한 table에 클래스 속성 추가
    table.setAttribute('class', 'menu-list-table');
    // dpl3로 생성한 ul의 바로 뒤에 JS 코드로 생성한 table을 삽입
    categories.parentNode.insertBefore( table, categories.nextSibling );
    // dpl3로 생성한 ul은 display:none 스타일 속성을 추가해 숨김
    categories.setAttribute('style', 'display:none;');
}

 

위와 같이 WIKI API를 통해서 다른 문서의 정보를 받아와, table을 임의로 구성해줄 수 있다!

또한 생성된 표는 'Mediawiki:Common.css' 를 프로젝트의 위키에서 검색하고, 편집하여 스타일을 부여해줄 수 있다.

단, 주의해야 할 점은 Common.js는 ES5와 특정 문법을 통해 JQuery까지만 제공하는 것으로 보인다.

 

 

[ 구현 결과 ]

구현 결과는 다음과 같다.

 

 

p.s.

미디어위키 API 사용방법 및 파라미터는 아래의 공식 링크를 참고하여 사용하면 된다.

 

 

API:대문 - MediaWiki

The following documentation is the output of Special:ApiHelp/main, automatically generated by the pre-release version of MediaWiki that is running on this site (MediaWiki.org). Main module Status: The MediaWiki API is a mature and stable interface that is

www.mediawiki.org

 

🤞 도움이 되셨기를 바랍니다. 한 번의 클릭과 댓글은 어딘가의 누군가에게 진실로 큰 힘이 됩니다. 🐱‍🏍

 

728x90
반응형

댓글