:빠른이동/app.js

리버티게임, 모두가 만들어가는 자유로운 게임
< 틀:빠른이동
BANIP (토론 | 기여)님의 2023년 7월 13일 (목) 21:06 판 (새 문서: (function(){ // 프리로딩 가능한 링크 최고 갯수 var previewLimit = 5; // 링크로 해당 문서 컨텐츠와 타이틀을 가져오는 프로미스 획득 var getParsedDocumentPromise = (function(){ var mwApi = new mw.Api(); return function(option){ var {href, fullPagename} = option; var searchParams = new URL(href).searchParams; var searchParamsObject = {}; searchParams.forEach(function...)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)

(function(){

   // 프리로딩 가능한 링크 최고 갯수
   var previewLimit = 5;

// 링크로 해당 문서 컨텐츠와 타이틀을 가져오는 프로미스 획득

   var getParsedDocumentPromise = (function(){
       var mwApi = new mw.Api(); 
       return function(option){
           var {href, fullPagename} = option;
           var searchParams = new URL(href).searchParams;
           var searchParamsObject = {};
           searchParams.forEach(function(value, key){
               // title 파라미터는 제외
               if(key === "title") return;
               searchParamsObject[key] = value;
           });
           // href에서 searchParams 추출
           return new Promise(function(resolve, reject){
               var apiParams = {
                   action: 'parse',
                   page: fullPagename,
                   formatversion: 2,
               };
               var requestOption = Object.assign(apiParams,searchParamsObject);
               mwApi.get(requestOption).then(function(data){
                   var title = data.parse.title;
                   var text = data.parse.text;
                   //text내에 #title-meta 요소가 포함되어 있으면 해당 컨텐츠를 title로 변경(제목틀 호환)
                   var $titleMeta = $(text).find("#title-meta");
                   if( $titleMeta.length > 0 ){
                       title = $titleMeta.html();
                   }
                   resolve({ title:title, text:text });
               }, function(e){
                   reject(e);
               }); 
           });
       };
   })();
   var setLoading = (function(){
       // 로딩창 표시 여부 플래그
       var timers = [];
       return function(isSetShow){
           // 이미 로딩 완료된 작업의 경우 로딩창을 표시하지 않기 위해
           // 로딩창 표시 작업시 예약 플래그를 설정하고 약간의 텀을 두기.
           if(isSetShow){
               setLoading.showFlag = true;
               var timer = setTimeout(function(){
                   if(setLoading.showFlag){
                       $("#loading").fadeIn(200);
                       // 타이머에서 제거
                       timers.splice(timers.indexOf(timer), 1);
                   }
               }, 50);
               timers.push(timer);
           } else {
           // 로딩창 삭제 작업시 표시작업이 예약되어있으면 같이 삭제
               setLoading.showFlag = false;
               $("#loading").fadeOut(200);
               timers.forEach(function(timer){
                   clearTimeout(timer);
               });
               timers = [];
           }
       };
   })();


   var toast = function(message){
       // 화면 오른쪽 하단에서 메세지 표시, 2초 후 사라짐

var $toast = $("

").addClass("toast").css({
           position:"fixed",
           bottom: "20px",
           right: "20px",
           padding: "10px 20px",
           background: "#000",
           color: "#fff",
           opacity: 0.8,
           boxShadow: "0 0 10px rgba(0,0,0,0.3)",
           zIndex: 9999,
           display: "none"
       });


       $toast.text(message).appendTo("body").fadeIn(200);
       setTimeout(function(){
           $toast.fadeOut(200, function(){
               $toast.remove();
           });
       }, 2000);
   };
   // 선행로딩된 페이지들
   var documentPromiseMap = {};
   var namespace = $("#firstHeading > span.mw-page-title-namespace").val() || "";

function getPagenameFromUrl(rawUrl){ var url = new URL(rawUrl, location.origin); // url의 searchParams에 title 파라미터가 있을 경우 해당 파라미터로 docname 지정 var fullPagename = url.searchParams.get("title") || "";

if(!fullPagename){ var matchedUrl = decodeURI(url.pathname).match(/[^\/]+\/(.*)/); if(matchedUrl){ // 문서명 파싱 성공시 문서명 지정 fullPagename = matchedUrl[1]; } else { // 문서명 파싱 실패시 모든 링크명 지정 fullPagename = decodeURI(url.pathname) } } // fullPagename에 ":"이 없을 경우 스트링 처음위치에 삽입 fullPagename = fullPagename.indexOf(":") === -1 ? `:${fullPagename}` : fullPagename;

// :를 기준으로 네임스페이스와 문서명 분리 var [namespace, pagename] = fullPagename.split(":"); return { namespace, pagename, fullPagename, } }

   function preloadDocument($doc){
       // 해당 링크의 action, title, oldid 파라미터가 없는 링크만 가져오기
       var targetLinkItems = $doc.find("a").not(".new")

// 대상이 되는 링크들만 필터링 .filter(function() { var href = this.href; if(href === "" || href.match(/^\#/) !== null) return false; // href가 없는 경우 제외 // 링크에서 가져온 url var url = new URL(href); var searchParams = url.searchParams; // 현재 url var nowUrl = new URL(location.href);

// 동일한 도메인이 아닌 경우 제외 if(url.origin !== nowUrl.origin) return false;

// 수정/리비전 확인 링크는 제외 if( ["action", "oldid"].some(function(key){ return searchParams.has(key); })) return false;

return true; }) // 필터링된 링크에 문서명 정보를 추가 .toArray().map(function(el) { var { namespace, pagename, fullPagename } = getPagenameFromUrl(el.href); return { el, href: el.href, namespace, pagename, fullPagename } }) // 동일한 네임스페이스만 이동되게 필터링 .filter(({namespace:thisNamespace}) => thisNamespace === namespace )


       // 필터된게 previewLimit 갯수 이상이면 동작 x, 프로미스맵에 클릭 시 로딩 필요함을 명시
       if(targetLinkItems.length > previewLimit){
           targetLinkItems.forEach(({href}) => {
               documentPromiseMap[href] ||= null
           });
       } else {
           // 필터링된게 프로미스맵에 없는 경우 사전 프리로딩 프로미스 추가
           targetLinkItems.forEach(({href, pagename, namespace}) => {
               documentPromiseMap[href] ||= getParsedDocumentPromise({href, fullPagename: `${namespace}:${pagename}`})
           });
       }
       
       // 가져온 링크로 전체 작업
       targetLinkItems.forEach(function(linkItem){

// 문서명 파싱 실패시 해당 링크 제외

           if(!linkItem) return;
           $(linkItem.el)
               .click(function(e){
                   e.preventDefault();

replaceBodyContent(this.href);

               });
       })
   };

async function replaceBodyContent(url, {urlChange = true} = {}){ var fullPagename = getPagenameFromUrl(url).fullPagename;

// 프리로드 불필요한 경우(네임스페이스가 다를때, 편집/리비전확인 링크일때) url 영구이동 if(documentPromiseMap[url] === undefined){ return location.href = url; } // 프리로드되지 않은 이동 가능한 링크면 로딩창 표시 후 해당 페이지 로딩 if(documentPromiseMap[url] === null){ documentPromiseMap[url] = getParsedDocumentPromise({href:url, fullPagename}); }

// 프로미스가 아직 안끝났으면 로딩창 표시 setLoading(true); // 링크 프로미스에 문제가 있을 시 다시 내용 확인, 성공시 문서 프로미스에 저장, 오류시 에러메세지 documentPromiseMap[url].then(function({title, text}){ // 프리로드 프로미스가 정상적으로 불러왔을 경우 let $thisDoc = $(text)

// 사전로딩된 내용에서 프리로드 분석 재실행 preloadDocument( $thisDoc ); $("#bodyContent").fadeOut(100, function(){ // 문서내용 교체 후 페이드 인 $("#firstHeading").html(title); // .vector-article-toolbar 내용물 링크 변경 필요 $(".mw-article-toolbar-container").find("a").each(function(){ try{ var $this = $(this); var href = $this.attr("href");

var url = new URL(href); url.searchParams.set("title", title); $this.attr("href", url.href); } catch (e){ } })

// 현재 url 변경 if(urlChange){ history.pushState(null, null, url); }

$("#bodyContent").html($thisDoc); $("#bodyContent").fadeIn(100); }) }).catch(function(e){ console.error(e) // 에러 발생 시 실패한 페이지 다시 프로미스에 저장 시도 documentPromiseMap[url] = null;

// 에러메세지 표시 toast('페이지 로딩에 실패했습니다. 다시 시도해주세요.'); }).finally(function(){ // 로딩창 삭제 setLoading(false); }); }

   (function main(){
       // #enable-preload div 없으면 동작 x
       if(!$(".mw-parser-output .enable-preload").length) return;
       // #bodyContent에 로딩창 추가
$("
").addClass("content-loading")
           .css({
               position: "absolute",
               top: 0,
               left: 0,
               width: "100%",
               height: "100%",
               background: "#fff",
               opacity: 0.8,
               zIndex: 9999,
               display: "none"
           })
           .attr("id", "loading")
.append($("
").css({
               position: "absolute",
               top: "50%",
               left: "50%",
               transform: "translate(-50%,-50%)"
           })
           .append($("로딩중")))
       .appendTo("#bodyContent");

// 현재 페이지 프리로드, 함수 내부에서 재귀적으로 프리로드 실행

       preloadDocument($("#mw-content-text > div.mw-parser-output"));

// url 변경 시(일반적으로 뒤로가기) 프리로드된 문서가 있으면 해당 문서로 이동( 2023년 7월 9일 (일) 14:00 (KST)기준 iOS/파폭에서 동작하지 않음 ) function handleNavigate(e){ // 사용자가 url 변경시에만 동작 if(e.navigationType === "traverse"){ replaceBodyContent(e.destination.url, {urlChange:false}); } } navigation.removeEventListener("navigate", handleNavigate); // 이벤트 중복 등록 방지 navigation.addEventListener("navigate", handleNavigate); // 이벤트 등록

   })();

})();