미디어위키:Common.js: 두 판 사이의 차이

리버티게임, 모두가 만들어가는 자유로운 게임
imported>Senouis
편집 요약 없음
잔글편집 요약 없음
(사용자 4명의 중간 판 47개는 보이지 않습니다)
1번째 줄: 1번째 줄:
/* -- 전역 상수 선언 -- */
// 미디어위키 폴더명 url 다뤄야되는 함수들에서 사용됨, 메인터넌스 거친 후 w 혹은 wiki로 변경 예정,
var wgScriptPath = "index.php";
/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */
/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */
/*<source lang="javascript"><nowiki>*/
/** [[틀:USERNAME]]에서 사용하는 바꿔치기 함수
  * 작성자: [[사용자:Peremen]]
*/
function UserNameReplace() {
    if (typeof(disableUsernameReplace) != 'undefined' && disableUsernameReplace) return;
    if (!document.getElementById('pt-userpage')) return;
    $("span.insertusername").each(function(i) {
        $(this).text(mw.config.get("wgUserName"))
    })
};
$(UserNameReplace);
/** 플러그인이 작동하지 않을 때 나타나는 내용
/** 플러그인이 작동하지 않을 때 나타나는 내용
  * js: noPlugin('(이름)');
  * js: noPlugin('(이름)');
34번째 줄: 22번째 줄:
  @param {object} location 획득할 로케이션 객체, 비어있으면 window.location을 참조
  @param {object} location 획득할 로케이션 객체, 비어있으면 window.location을 참조
  원작성자: [[사용자:BANIP|BANIP]]
  원작성자: [[사용자:BANIP|BANIP]]
현 편집자: [[사용자:hsl0|hsl0]]
*/
*/
function geturlSearch(location) {
function geturlSearch(location) {
location = location || window.location;
if(!location) location = window.location;
var result = {};
else if(typeof location === 'string') location = new URL(location);
if(location.search) decodeURIComponent(location.search)
    var result = {};
.substring(1)
    if (location.search)
.split("&")
        location.search.substring(1).replace(/\+/g, ' ').split("&").map(function(v) {
.map(function(v) { return v.split("=") })
            return v.split("=");
.forEach(function(v) { result[v[0]] = v[1] });
        }).forEach(function(v) {
return result;url.hash = encodeURIComponent(hash);
            result[decodeURIComponent(v[0])] = decodeURIComponent(v[1]);
        });
    return result;
}
}


/* 객체형태로 된 SearchParam을 받아 string형태로 반환
/* 객체형태로 된 SearchParam을 받아 string형태로 반환
76번째 줄: 69번째 줄:
});
});


/** [[틀:제목]]에서 사용하는 제목 바꿔치기 함수
* 작성자: [[사용자:Peremen|Peremen]]
*/
/*
function rewriteTitle() {
    if (typeof(disableTitleRewrite) != 'undefined' && disableTitleRewrite) return;
    if (!document.getElementById('title-meta')) return;
    $('h1.firstHeading').each(function(i) {
        $(this).html($("#title-meta").html()).css('text-align', $("#title-align").text());
    });
}
$(rewriteTitle);
*/
/* from en: */
var hasClass = (function() {
    var reCache = {};
    return function(element, className) {
        return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className);
    };
})();
/* ([[위키백과:관리자 요청/2007년 5월#스크립트 추가 요청]]) */
/** Collapsible tables *********************************************************
*
*  Description: Allows tables to be collapsed, showing only the header. See
*              Wikipedia:NavFrame.
*  Maintainers: User:R. Koot
*/
//var autoCollapse = 2;
//var collapseCaption = "hide";
//var expandCaption = "show";
function collapseTable(tableIndex) {
    var Button = document.getElementById("collapseButton" + tableIndex);
    var Table = document.getElementById("collapsibleTable" + tableIndex);
    if (!Table || !Button) {
        return false;
    }
    var Rows = Table.getElementsByTagName("tr");
    if (Button.firstChild.data == collapseCaption) {
        for (var i = 1; i < Rows.length; i++) {
            Rows[i].style.display = "none";
        }
        Button.firstChild.data = expandCaption;
    } else {
        for (var i = 1; i < Rows.length; i++) {
            Rows[i].style.display = Rows[0].style.display;
        }
        Button.firstChild.data = collapseCaption;
    }
}
function createCollapseButtons() {
    var tableIndex = 0;
    var NavigationBoxes = new Object();
    var Tables = document.getElementsByTagName("table");
    for (var i = 0; i < Tables.length; i++) {
        if (hasClass(Tables[i], "collapsible")) {
            NavigationBoxes[tableIndex] = Tables[i];
            Tables[i].setAttribute("id", "collapsibleTable" + tableIndex);
            var Button = document.createElement("span");
            var ButtonLink = document.createElement("a");
            var ButtonText = document.createTextNode(collapseCaption);
            Button.style.styleFloat = "right";
            Button.style.cssFloat = "right";
            Button.style.fontWeight = "normal";
            Button.style.textAlign = "right";
            Button.style.width = "6em";
            ButtonLink.setAttribute("id", "collapseButton" + tableIndex);
            ButtonLink.setAttribute("href", "javascript:collapseTable(" + tableIndex + ");");
            ButtonLink.appendChild(ButtonText);
            Button.appendChild(document.createTextNode("["));
            Button.appendChild(ButtonLink);
            Button.appendChild(document.createTextNode("]"));
            var Header = Tables[i].getElementsByTagName("tr")[0].getElementsByTagName("th")[0];
            /* only add button and increment count if there is a header row to work with */
            if (Header) {
                Header.insertBefore(Button, Header.childNodes[0]);
                tableIndex++;
            }
        }
    }
    for (var i = 0; i < tableIndex; i++) {
        if (hasClass(NavigationBoxes[i], "collapsed") || (tableIndex >= autoCollapse && hasClass(NavigationBoxes[i], "autocollapse"))) {
            collapseTable(i);
        }
    }
}
$(createCollapseButtons);
/** ([[위키백과:관리자 요청/2007년 5월#스크립트 추가 요청]])
* 이 스크립트는 위키백과 펌이므로, 위키백과 라이선스인 CCL BY-SA가 적용됩니다.
*/
/** Dynamic Navigation Bars (experimental) *************************************
*
*  Description: See [[:en:Wikipedia:NavFrame]].
*  Maintainers: UNMAINTAINED
*/
// set up the words in your language
var autoCollapse = 2;
var collapseCaption = "숨기기";
var expandCaption = "보이기";
var NavigationBarHide = '[' + collapseCaption + ']';
var NavigationBarShow = '[' + expandCaption + ']';
// set up max count of Navigation Bars on page,
// if there are more, all will be hidden
// NavigationBarShowDefault = 0; // all bars will be hidden
// NavigationBarShowDefault = 1; // on pages with more than 1 bar all bars will be hidden
var NavigationBarShowDefault = autoCollapse;
// shows and hides content and picture (if available) of navigation bars
// Parameters:
//    indexNavigationBar: the index of navigation bar to be toggled
function toggleNavigationBar(indexNavigationBar) {
    var NavToggle = document.getElementById("NavToggle" + indexNavigationBar);
    var NavFrame = document.getElementById("NavFrame" + indexNavigationBar);
    if (!NavFrame || !NavToggle) {
        return false;
    }
    // if shown now
    if (NavToggle.firstChild.data == NavigationBarHide) {
        for (
            var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling
        ) {
            if (hasClass(NavChild, 'NavPic')) {
                NavChild.style.display = 'none';
            }
            if (hasClass(NavChild, 'NavContent')) {
                NavChild.style.display = 'none';
            }
        }
        NavToggle.firstChild.data = NavigationBarShow;
        // if hidden now
    } else if (NavToggle.firstChild.data == NavigationBarShow) {
        for (
            var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling
        ) {
            if (hasClass(NavChild, 'NavPic')) {
                NavChild.style.display = 'block';
            }
            if (hasClass(NavChild, 'NavContent')) {
                NavChild.style.display = 'block';
            }
        }
        NavToggle.firstChild.data = NavigationBarHide;
    }
}
// adds show/hide-button to navigation bars
function createNavigationBarToggleButton() {
    var indexNavigationBar = 0;
    // iterate over all < div >-elements
    var divs = document.getElementsByTagName("div");
    for (var i = 0; NavFrame = divs[i]; i++) {
        // if found a navigation bar
        if (hasClass(NavFrame, "NavFrame")) {
            indexNavigationBar++;
            var NavToggle = document.createElement("a");
            NavToggle.className = 'NavToggle';
            NavToggle.setAttribute('id', 'NavToggle' + indexNavigationBar);
            NavToggle.setAttribute('href', 'javascript:toggleNavigationBar(' + indexNavigationBar + ');');
            var NavToggleText = document.createTextNode(NavigationBarHide);
            NavToggle.appendChild(NavToggleText);
            // Find the NavHead and attach the toggle link (Must be this complicated because Moz's firstChild handling is borked)
            for (
                var j = 0; j < NavFrame.childNodes.length; j++
            ) {
                if (hasClass(NavFrame.childNodes[j], "NavHead")) {
                    NavFrame.childNodes[j].appendChild(NavToggle);
                }
            }
            NavFrame.setAttribute('id', 'NavFrame' + indexNavigationBar);
        }
    }
    // if more Navigation Bars found than Default: hide all
    if (NavigationBarShowDefault < indexNavigationBar) {
        for (
            var i = 1; i <= indexNavigationBar; i++
        ) {
            toggleNavigationBar(i);
        }
    }
}
$(createNavigationBarToggleButton);
/** 대문의 탭을 "프로젝트"->"대문"으로 바꾸는 함수.
* 작성자: [[사용자:Peremen|Peremen]]
*/
function MainPageRenameNamespaceTab() {
    var hasMainPageTab = document.getElementsByClassName("hasMainPageTab");
    if (hasMainPageTab[0] !== undefined) {
        $('#ca-nstab-project a').text("대문");
    }
    var title = mw.config.get('wgPageName');
    var hasGameListTab = (title == '백괴게임:게임_목록' || title == '백괴게임토론:게임_목록');
    if (hasGameListTab) {
        $('#ca-nstab-project a').text("게임 목록");
    }
    $('#ca-nstab-main a').text("게임");
}
$(MainPageRenameNamespaceTab);
/** 임베드 플래시 무비
* 문서에 플래시 파일을 넣을 수 있게 합니다. [[틀:플래시]]를 참고하십시오.
* 원작성자: [[:en:User:Olipro|Olipro]]
*/
// 플래시 사용 중지에 따라 이 기능은 비활성화됩니다.
/*
function useFlash() {
    var flashOk;
    var contentTempHolder;
    $(embedFlashCheck);
}
function embedFlashMovie(flashOk) {
    mainbody = document.getElementById('bodyContent');
    mainbody.innerHTML = contentTempHolder;
    spancheck = document.getElementsByTagName('span');
    for (i = 0; i < spancheck.length; i++) {
        if (spancheck[i].getAttribute('id') != 'embedFlashDoc') {
            continue;
        }
        obj = spancheck[i].innerHTML.split('@');
        flwidth = obj[0];
        flheight = obj[1];
        flfile = obj[2].replace('fullurl://', 'https://');
        showFlash = ' ';
        if (flashOk) {
            showFlash = '<object width="' + flwidth + '" height="' + flheight + '"';
            showFlash += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"';
            showFlash += 'codebase="http://fpdownload.macromedia.com/pub/';
            showFlash += 'shockwave/cabs/flash/swflash.cab#version=8,0,0,0">';
            showFlash += '<param name="movie" value="' + flfile + '" />';
            showFlash += '<embed src="' + flfile + '" width="' + flwidth + '" height=';
            showFlash += '"' + flheight + '" type="application/x-shockwave-flash" ';
            showFlash += 'pluginspage="http://www.macromedia.com/go/getflashplayer" />';
            showFlash += '</object>';
        } else {
            showFlash = '<a class="plainlinks" href="javascript:embedFlashMovie(true)" onClick="embedFlashMovie(true)">' + flfile + '</a> (신뢰하는 경우 보려면 클릭하십시오.)';
        }
        spancheck[i].innerHTML = showFlash;
        spancheck[i].style.display = 'inline';
    }
}
function embedFlashCheck() {
    if (!document.getElementById('embedFlashDoc')) {
        return;
    }
    mainbody = document.getElementById('bodyContent');
    contentTempHolder = mainbody.innerHTML;
    if (typeof displayFlashOverride != 'undefined') {
        embedFlashMovie(displayFlashOverride);
        return;
    }
    askmessage = '<div align="center" id="askflash">이 게임에는 ';
    askmessage += '<a href="/wiki/백괴:플래시" class="plainlinks">플래시</a>가 들어있습니다.<br />';
    askmessage += '컴퓨터에 해를 끼칠 수 있으므로 신뢰하는 경우에만 여십시오.<br />';
    askmessage += '플래시가 포함된 게임을 보시겠습니까?<br><b> ';
    askmessage += '<a href="javascript:embedFlashMovie(true)" ';
    askmessage += 'onClick="embedFlashMovie(true)">예</a> | <a ';
    askmessage += 'href="https://libertygame.miraheze.org/">아니오</a>';
    mainbody.innerHTML = askmessage;
}
$(useFlash);
*/
/* userAgent */
/* userAgent */
/** source: http://www.gregoryvarghese.com/how-to-get-browser-name-and-version-via-javascript/ **/
/** source: http://www.gregoryvarghese.com/how-to-get-browser-name-and-version-via-javascript/ **/
380번째 줄: 84번째 줄:


     if (M[1] === 'Chrome') {
     if (M[1] === 'Chrome') {
         tem = ua.match(/\bOPR\/(\d+)/)
         tem = ua.match(/\bOPR\/(\d+)/);
         if (tem != null) {
         if (tem != null) {
             return {
             return {
402번째 줄: 106번째 줄:
}
}


/** DB기능 초기화
* [[틀:DB]]를 사용 가능하게 해 줍니다.
* 원작성자: [[사용자:BANIP|BANIP]]
*/
function enableLocalStorage() {
    // 문서 미리보기 상태일 시 종료
    var searchParams = geturlSearch(location);
    var isNormalMode =
        searchParams.action === undefined &&
        searchParams.curid ===  undefined &&
        searchParams.oldid === undefined &&
        searchParams.direction === undefined &&
        searchParams.printable === undefined &&
        searchParams.diff === undefined ;
if (!(isNormalMode)) return "";
    //플러그인의 모든 키 순회
    function forEach(object, callback) {
        for (var key in object) {
            var variable = object[key];
            callback(variable, key);
        }
    }
    function setLocalStorage(parentKey, datas) {
        var stringKeys = JSON.stringify(Object.keys(datas));
        localStorage.setItem(parentKey + "/__keys__", stringKeys);
        forEach(datas, function(v, i) {
            if (i === "action") return;
            localStorage.setItem(parentKey + "/" + i, v);
        });
    }
    function getLocalStorage(parentKey) {
        var datas = {};
        var stringKeys = localStorage.getItem(parentKey + "/__keys__");
        if (stringKeys === null) return null;
        var keys = JSON.parse(stringKeys);
        keys.forEach(function(key) {
            datas[key] = localStorage.getItem(parentKey + "/" + key);
        })
        return datas;
    }
    function clearLocalStorage(parentKey) {
        var datas = {};
        var stringKeys = localStorage.getItem(parentKey + "/__keys__");
        if (stringKeys === null) return null;
        var keys = JSON.parse(stringKeys);
        keys.forEach(function(key) {
            datas[key] = localStorage.removeItem(parentKey + "/" + key);
        })
    }
    function getSearch() {
        return geturlSearch();
    }
function searchParamToString(searchParamsObj){
var params = "?" + Object.entries(searchParamsObj)
.map(function(v){ return v.join("=") })
.join("&");
return encodeURI(params);
}
    function setSearch(datas) {
        var searchParams = getSearch();
        forEach(datas, function(v, i) {
            searchParams[i] = v;
        });
        location.search = searchParamToString(searchParams);
    }
    function hasSearch() {
        return !(location.search === "");
    }
    $(".controlLocalStorage").each(function() {
        var parentKey = $(this).data("key");
        var behavior = $(this).data("behavior");
        switch (behavior) {
            case "세이브":
                if (!hasSearch()) return;
                var datas = getSearch();
                clearLocalStorage(parentKey);
                setLocalStorage(parentKey, datas);
                break;
            case "로드":
                if (hasSearch()) return;
                var datas = getLocalStorage(parentKey, datas);
                if (datas === null) return;
                setSearch(datas);
                break;
            case "초기화":
            clearLocalStorage(parentKey);
            break;
        }
    })
}
$(enableLocalStorage);
/* DB기능 초기화 끝 */
/** [[틀:CGI2]] 변수 구문 해석기
* 작성자: [[사용자:Gustmd7410]]
**/
var CGI2Parser = (function() {
function CGI2Parser(actions) {
// new 키워드 미사용시
if(!(this instanceof CGI2Parser)) {
console.warn("CGI2Parser 객체를 new 키워드 없이 생성했습니다");
return new CGI2Parser(actions);
}
if(typeof actions === "object") this.actions = actions;
else if(actions === undefined) this.actions = {};
else throw new TypeError("생성자 CGI2Parser의 첫번째 변수가 객체가 아닙니다");
}
CGI2Parser.prototype.parse = function parse(origin, params, useStrict) {
var actions = this.actions;
JSON.parse(params.replace(/\,\s*\]/, "]")).forEach(function(command, useStrict) {
var wrapper = Object.entries(command)[0];
var action = actions[wrapper[0]];
var arg = wrapper[1];
if(typeof action === "function") {
origin = actions[wrapper[0]].apply(origin, Array.isArray(arg)? arg : [arg]) || origin;
} else if(!useStrict) {
return;
} else if(action === undefined) {
origin = new TypeError('동작 "' + wrapper[0] + '"이(가) 존재하지 않습니다');
origin.name = "ActionNoExistError";
throw origin;
} else {
origin = new TypeError('동작 "' + wrapper[0] + '"은(는) 유효하지 않는 타입(' + typeof action + ') 입니다');
origin.name = "ActionWrongTypeError";
throw origin;
}
});
return origin;
};
return CGI2Parser;
})();
/* [[틀:CGI2]] 변수 구문 해석기 끝 */
/** [[틀:CGI2|CGI2]]를 사용 가능하게 만드는 jquery 구문
* 원작성자: [[사용자:BANIP|BANIP]]
* 2차 작성자: [[사용자:Gustmd7410|Gustmd7410]]
**/
function useCGI2() {
$(".cgilink").each(function() {
// CGI2의 page속성과 data속성을 가져옴
var page = $(this).data("page").split('#');
var variables = $(this).data("var");
// 가져온 page데이터 속성을 조합해 url인스턴스 생성
var pagename = page.shift() || mw.config.get('wgPageName');
var hash = page.join('#');
var urlstr = window.location.origin;
var url = new URL(urlstr);
var searchParam = geturlSearch();
// 엄격모드 사용여부 결정
if(typeof useCGI2.useStrict !== "boolean") {
useCGI2.useStrict = (searchParam.debug === "true" || searchParam.debug == 1)? true : false;
}
// 가져온 var속성으로 url 인스턴스의 searchparams를 씹고 뜯고 맛보고 즐기고
var enabledKey = null;
try {
searchParam = new CGI2Parser({
set: function(key, value) {
this[key.trim()] = value.trim();
},
"default": function(key, value) {
key = key.trim();
this[key] = this[key] || value.trim();
},
del: function(key) {
delete this[key.trim()];
},
restrict: function(key) {
if(!enabledKey) enabledKey = [];
enabledKey.push(key);
}
}).parse(searchParam, variables, useCGI2.useStrict);
if(enabledKey) Object.keys(searchParam).forEach(function(key) {
if(!enabledKey.includes(key)) delete searchParam[key];
});
} catch(error) {
$(this).html($("<span class='error' />").text(error.message));
return;
}
// url 경로 조정
if(Object.keys(searchParam).length > 0) {
url.pathname = "/w/index.php";
searchParam.title = pagename;
} else url.pathname = "/wiki/" + mw.util.wikiUrlencode(pagename);
url.search = searchParamToString(searchParam);
url.hash = mw.util.escapeIdForLink(hash);
// cgilink에 a태그 추가
var children = $(this).html();
$(this).html("<a href='" + url.href.replace("'", "&#39;") + "'>" + children + "</a>");
});
}
/*
true = 항상 엄격모드
null = 디버그 모드 (debug=true) 에 엄격모드 자동 전환
false = 엄격모드 사용 안함
*/
useCGI2.useStrict = null;
$(useCGI2);
/* [[틀:CGI2|CGI2]]를 사용 가능하게 만드는 jquery 구문 끝 */
/** mediawiki api를 통해 간단하게 문서들을 수집, 변경하는 함수.
* 플러그인 코어에서 사용하기 위해 만들었습니다.
* 원작성자: [[사용자:BANIP|BANIP]], 수정자: [[사용자:Bd3076|Bd3076]]
* 사용방법
*: var api = MediaWikiAPI(); .changeDocument()
*: api.changeDocument(변경할 문서의 타이틀, 편집 요약, 변경할 문서의 내용) => 문서의 내용을 변경합니다.
*: api.addDocument(변경할 문서의 타이틀, 편집 요약, 추가할 문서의 내용) => 문서에 새로운 내용을 추가합니다.
*: api.getDocument(가져올 문서의 타이틀) => 문서의 모든 텍스트를 읽어옵니다.
*: api.readDocument(가져올 문서의 타이틀) => 문서의 모든 텍스트를 jquery 객체로 읽어옵니다.
* 영 좋지 않은 목적으로 사용 하면 안드로메다 경찰관이 잡아간다!
*/
function MediaWikiAPI() {
    var token;
    var getToken = function() {
        if (token !== undefined) return token;
        $.ajax({
            url: "/w/api.php?action=query&meta=tokens",
            success: function(v, i) {
                var datas = JSON.parse($(v).find("pre").text());
                token = datas["query"]["tokens"]["csrftoken"];
            },
            async: false
        });
        return token;
    };
    function changeDocument(title, summary, content, isUnReload, minor) {
    mw.loader.using( ['mediawiki.util','mediawiki.Title'] ).then( function () {
    $.ajax({
            url: mw.util.wikiScript("api"),
            data: {
                format: 'json',
                action: 'edit',
                title: title,
                summary: summary,
                text: content,
                minor: minor,
                token: getToken(),
            },
            dataType: 'json',
            type: 'POST',
            success: function(data) {
                if (data && data.edit && data.edit.result == 'Success') {
                    if (!isUnReload) window.location.reload(); // reload page if edit was successful
                } else if (data && data.error) {
                    alert('Error: API returned error code "' + data.error.code + '": ' + data.error.info);
                } else {
                    alert('Error: Unknown result from API.');
                }
            },
            error: function(xhr) {
                alert('Error: Request failed.');
            }
        });
} );
    }
    function addDocument(title, summary, content, isUnReload, minor) {
        originContent = getDocument(title);
        changeDocument(title, summary, originContent + content, isUnReload, minor);
    }
    function getDocument(title) {
        function entityDecode(doc) {
            return $('<p></p>').html(doc).text();
        }
        var originContent;
        $.ajax({
            url: "/w/index.php?title=" + title + "&action=edit",
            success: function ajaxSucess(data) {
                originContent = $(data).find("textarea").html();
            },
            async: false
        });
        return entityDecode(originContent);
    }
    function readDocument(title) {
        var doc;
        $.ajax({
            url: "/wiki/" + title,
            success: function ajaxSucess(data) {
                doc = $(data).find("#mw-content-text");
            },
            async: false
        });
        return doc;
    }
    return {
        getToken: getToken,
        changeDocument: changeDocument,
        addDocument: addDocument,
        getDocument: getDocument,
        readDocument: readDocument,
    };
}
/* DB 기능 초기화 끝 */
/** [[틀:플러그인]]을 사용 가능하게 해 줍니다. 사용자의 허락을 맡고 사용자의 commonjs 편집을 허가 할 수 있는 문서입니다.
* 작성자: [[사용자:BANIP|BANIP]]
* [[백괴게임:관리자 요청/2018년 1월]]에서 BANIP님 요청으로 퍼왔습니다.
*/
function pluginCore() {
    // 사용자의 commonjs의 문서 이름을 획득
    var commonjs = "사용자:" + mw.config.get("wgUserName") + "/common.js";
    var plugins = {},
        docPlugins = {},
        uninstalledPlugins = {},
        unupdatedPlugins = {};
    var preloadedplugins = [],
        needPlugins = [];
    var api = MediaWikiAPI();
    var jsdoc = api.getDocument(commonjs);
    //commonjs에서 특정 플러그인 제거
    function removePluginByDoc(pluginTitle, doc) {
        var reg = new RegExp("\\/\\*\\* 플러그인 " + pluginTitle + "([\\s\\S]*)\\/\\* " + pluginTitle + " 끝 \\*\\/", "g");
        doc = doc.replace(reg, "");
        return doc
    }
    // 플러그인이 비어있는지 확인
    function isPluginsEmpty(plugins) {
        return Object.keys(plugins).length === 0;
    }
    //플러그인의 모든 키 순회
    function forEach(object, callback) {
        for (var key in object) {
            var variable = object[key];
            callback(variable, key);
        }
    }
    // 문서에서 사용하는 플러그인들을 체크합니다. use-script클래스를 가진 모든 돔 요소를 조사하고
    // 그 돔에 내장된 플러그인 데이터를 docPlugins에 추가합니다.
    var checkDocPlugin = (function(docPlugins) {
        function getPluginData($this) {
            return {
                name: $this.attr("data-name"), // 플러그인 이름
                descript: $this.attr("data-descript"), // 플러그인 내용
                version: $this.attr("data-version"), // 플러그인 이름
                local: ($this.attr("data-local") === "true") ? true : false,
                creat: $this.attr("data-creat"),
                state: $this.attr("data-state"),
                link: $this.attr("data-link"),
                executable: $this.attr("data-executable") === "true" ? true : false,
            };
        }
        function getAllPluginsName(plugins) {
            var pluginNames = [];
            forEach(plugins, function(plugin) {
                var pluginName = plugin.name;
                pluginNames.push(pluginName);
            })
            return pluginNames;
        }
        var loadAllPlugins = (function(docPlugins) {
            $(".use-script").each(function() {
                const plugin = getPluginData($(this));
                docPlugins[plugin.name] = plugin;
            })
        })(docPlugins)
        var loadAllPlugins = (function(docPlugins) {
            if (!isPluginsEmpty(docPlugins)) {
                var subTitle = " " + getAllPluginsName(docPlugins).join(", ") + " 플러그인 가동중";
                $("#siteSub").text(function(i, v) {
                    return v + subTitle
                });
            }
        })(docPlugins)
    })(docPlugins);
    // 사용자가 가지고 있는 플러그인들을 체크합니다.
    var checkHavePlugin = (function() {
        function getUserPlugins(jsdoc) {
            var userplugins = [];
            // plugins.---가 있는지 체크하는 정규식
            var pluginreg = /JSON \=\> ([\S]+) = (\{.*\})/g;
            var nameMatch = pluginreg.exec(jsdoc);
            while (nameMatch) {
                userplugins.push(JSON.parse(nameMatch[2]));
                nameMatch = pluginreg.exec(jsdoc);
            }
            return userplugins;
        }
        function isSamePlugin(pluginFirst, pluginSecond) {
            return pluginFirst.name == pluginSecond.name
        }
        function isSameVersionPlugin(pluginFirst, plugiSecond) {
            return pluginFirst.version == plugiSecond.version
        }
        function addNeedPlugins(targetPlugins) {
            //global docPlugins, needPlugins
            for (var key in targetPlugins) {
                var pluginName = docPlugins[key].name;
                needPlugins.push(pluginName);
            }
        }
        if (!isPluginsEmpty(docPlugins)) {
            preloadedplugins = getUserPlugins(jsdoc);
            forEach(docPlugins, function(docplugin) {
                var isHavePlugin = false;
                forEach(preloadedplugins, function(myplugin) {
                    if (!isSamePlugin(docplugin, myplugin)) return;
                    if (!isSameVersionPlugin(docplugin, myplugin)) {
                        unupdatedPlugins[docplugin.name] = docplugin;
                    }
                    isHavePlugin = true;
                });
                if (!isHavePlugin) {
                    uninstalledPlugins[docplugin.name] = docplugin;
                }
            });
            addNeedPlugins(uninstalledPlugins);
            addNeedPlugins(unupdatedPlugins);
        }
    })();
    function onPluginInstall() {
        function getPluginCode(plugin) {
            // html로 구성된 코드를 텍스트로
            function entityDecode(doc) {
                return $('<p></p>').html(doc).text();
            }
            function getDocHead(plugin) {
                var docHead = "";
                var toJSONPlugin = Object.assign({}, plugin);
                toJSONPlugin.code = undefined;
                toJSONPlugin.link = undefined;
                docHead += "\n"
                docHead += "\n/** 플러그인 " + plugin["name"] + "***************************\n";
                docHead += "* " + plugin["descript"] + "\n";
                docHead += "* 버전 => " + plugin["version"] + "\n";
                docHead += "* 작성자 : [[사용자:" + plugin["creat"] + "|" + plugin["creat"] + "]] \n";
                docHead += "* JSON => " + plugin["name"] + " = " + JSON.stringify(toJSONPlugin) + "; \n";
                docHead += "*/ \n";
                docHead += "function plugin_" + plugin["name"] + "(){\n";
                if (plugin.local) docHead += "  if($(\"[data-name='" + plugin["name"] + "']\").length >= 1){\n";
                return docHead;
            }
            function getDocFoot(plugin) {
                var docFoot = "";
                if (plugin.local) docFoot += "\n  }\n";
                docFoot += "\n}\n";
                if (plugin.executable) docFoot += "$( plugin_" + plugin["name"] + " );\n";
                docFoot += "/* " + plugin["name"] + " 끝 */\n\n";
                return docFoot;
            }
            var docHead = getDocHead(plugin),
                docFoot = getDocFoot(plugin);
            return entityDecode(docHead + plugin["code"] + docFoot);
        }
        $(".install-button").text("설치중..");
        $(".install-button").off("click");
        var doc = "";
        forEach(needPlugins, function(pluginName) {
            var plugin = docPlugins[pluginName];
            jsdoc = removePluginByDoc(pluginName, jsdoc);
            doc += getPluginCode(plugin);
        });
        api.changeDocument(commonjs, "플러그인 " + needPlugins + "설치", jsdoc + doc);
    }
    var checkinstalledPlugin = function() {
        function appendBox(plugin, status) {
            var pluginName = plugin.name;
            var box = $(".cloneable.p-box").clone().removeClass("cloneable");
            var code = api.readDocument(plugin.state).find("pre.script").html();
            docPlugins[pluginName].code = code;
            box.find(".p-status").html(status);
            box.find(".p-code").html(code.replace(/\s{1,}$/, ""));
            box.find(".p-name").text(pluginName);
            box.find(".p-descript").text(plugin["descript"]);
            if (status == "버전업") {
                var thisVersion;
                for (var key in preloadedplugins) {
                    if (preloadedplugins[key].name == plugin["name"]) {
                        thisVersion = preloadedplugins[key].version;
                    }
                }
                box.find(".p-version").text(thisVersion + " => " + plugin["version"]);
            } else {
                box.find(".p-version").text(plugin["version"]);
            }
            box.find(".p-local").text(plugin["local"] == true ? "일부 문서만" : "문서 전체");
            box.find(".p-creat").text(plugin["creat"]);
            $.ajax({
                url: "/w/api.php?action=query&prop=revisions&rvdir=older&titles=" + plugin.state,
                success: function(v, i) {
                    var datas = JSON.parse($(v).find("pre").text());
                    var titleKey = Object.keys(datas["query"]["pages"])[0];
                    var lastModified = datas["query"]["pages"][titleKey]["revisions"][0]["user"] + "(" + datas["query"]["pages"][titleKey]["revisions"][0]["timestamp"] + ")";
                    box.find(".p-last").text(lastModified);
                },
                async: false
            })
            $(".box-article").append(box);
        }
        if (isPluginsEmpty(docPlugins) || (isPluginsEmpty(unupdatedPlugins) && isPluginsEmpty(uninstalledPlugins))) return;
        var doc = $("#mw-content-text");
        var setupMeta = api.readDocument("틀:플러그인/setup");
        doc.html(setupMeta);
        forEach(uninstalledPlugins, function(uninstalledPlugin) {
            appendBox(uninstalledPlugin, "설치");
        });
        forEach(unupdatedPlugins, function(unupdatedPlugin) {
            appendBox(unupdatedPlugin, "버전업");
        });
        $(".install-button").on("click", onPluginInstall);
    }
    var showPluginTemplet = (function() {
        if (isPluginsEmpty(needPlugins)) {
            return;
        }
        if ($(".plugin-install").length >= 1) {
            $(".plugin-install").eq(0).closest("table").show();
            $(".plugin-name").eq(0).text(needPlugins);
            $(".plugin-install").on("click", checkinstalledPlugin);
        } else {
            checkinstalledPlugin();
        }
    })();
}
$(pluginCore)
/** paramtest 함수
* [[틀:CGI2|CGI2]] 등에 적용되는 searchParams 메소드 지원 여부를 판단하는 함수
* 작성자: [[사용자:Manymaster|manymaster]]
*/
function paramtest() {
    var test_code;
    var Params = new URL(document.location).searchParams;
    if (Params === undefined) {
        test_code = 0;
    } else {
        test_code = 1;
    }
    return test_code;
}
/** paraminfo 함수
* paramtest의 부속 함수로 searchParams 메소드 지원시 지정한 메시지를 숨길 수 있게 해주는 함수
* 메시지는 searchparam_test 클래스로 지정하여 숨길 수 있습니다. */
function paraminfo() {
    var test_code = paramtest();
    if (test_code == 0) {
        return;
    } else {
        for (var i = 0; i < document.getElementsByClassName("searchparam_test").length; i++) {
            document.getElementsByClassName("searchparam_test")[i].style.display = "none";
        }
    }
}
$(paraminfo);
/* paramtest 및 부속 함수 끝 */
/** [[틀:편집불가]] 재 리뉴얼용 함수
* [[틀:편집불가]]의 브라우저 및 모니터 차별, 3대 원칙 위반 가능 요소 포함 등으로 리뉴얼을 했으나, 리뉴얼한 틀을 소화 못하는 게임이 많아보이는 관계로 재 리뉴얼 합니다.
* 작성자: [[사용자:Manymaster|manymaster]]
*/
function editprevent() {
    var caprevent = document.getElementsByClassName("edit-prevent");
    var cahisprevent = document.getElementsByClassName("history-prevent");
    if (caprevent[0] === undefined || caprevent[0] === null) {
    return;
    } else {
        if (cahisprevent[0] === undefined || cahisprevent[0] === null) {
            cahisprevent = document.getElementsByClassName("edit-prevent");
            }
        var caedit = document.getElementById('ca-edit');
        var cahistory = document.getElementById('ca-history');
        var caviewsource = document.getElementById('ca-viewsource');
        if (caedit !== null && caedit !== undefined){
            caedit.innerHTML = caprevent[0].innerHTML;
            cahistory.innerHTML = cahisprevent[0].innerHTML;
        } else {
            caviewsource.innerHTML = caprevent[0].innerHTML;
            cahistory.innerHTML = cahisprevent[0].innerHTML;
        }
    }
    return;
}
$( editprevent );
/* [[틀:편집불가]] 재 리뉴얼용 함수 끝 */
/** 스크립트의 함수를 실행시키는 링크 만들기
* $('(객체)').each(function() {
      scriptLink(this);
      $(this).click(function () {
          (함수)
      });
  });
* 작성자: [[사용자:Gustmd7410|Gustmd7410]] */
function scriptLink(element) {
    $(element).html('<a>' + $(element).html() + '</a>');
}
/** [[틀:고급 넘겨주기]]에서 사용하는 넘겨주기 함수
* id="advredirect" data-url="(문서명)"
* 작성자: [[사용자:Gustmd7410|Gustmd7410]] */
$('#advredirect').each(function() {
location.replace(location.origin + $(this).data('url'));
});
/** [[틀:비밀링크]]에서 사용하는 리다이렉트 링크 함수
* class="clearlink" data-url="(문서명)"
* 작성자: [[사용자:Gustmd7410|Gustmd7410]] */
$('.clearlink').each(function() {
    scriptLink(this);
    $(this).click(function() {
        location.replace(location.origin + $(this).data('url'));
    });
});
/** [[틀:뒤로]], [[틀:새로고침]], [[틀:앞으로]]에서 사용하는 방문기록 이동 함수
* class="historygo" data-url="(문서명)"
* 작성자: [[사용자:Gustmd7410|Gustmd7410]] */
$('.historygo').each(function() {
    scriptLink(this);
    $(this).click(function() {
        history.go($(this).data('page'));
    });
});
/** [[특수:올리기]]에 파일 정보 틀 자동 로드
* [[w:특수:고유링크/20640234]] 이 스크립트는 위키백과 펌이므로, 위키백과 라이선스인 CCL BY-SA가 적용됩니다.
*/
function uploadPreload() {
// 새 버전 올리기일 때 동작 안 함
if (mw.util.getParamValue('wpForReUpload') !== null) return;
// 설명란이 있고 비어있을 때 내용 변경
var desc = document.getElementById('wpUploadDescription');
if(desc !== null && desc.value === '' ) {
desc.value = '{\{파일 정보\n|설명 = \n|출처 = \n|날짜 = \n}}\n';
}
}
jQuery( document ).ready(uploadPreload);
/* [[특수:올리기]]에 파일 정보 틀 자동 로드 끝 */
/** [[틀:로고 바꾸기]]용 함수 V 1.1
* 작성자: [[사용자:Manymaster|manymaster]],
* 1.1 업데이트: [[사용자:BANIP|BANIP]]
*/
function logochange() {
// 허용 확장자 및 url 패턴
    var allwedURLPattern = ["i.uncyclopedia.kr/game/","i.uncyclopedia.kr/pedia/","upload.wikimedia.org/wikipedia/commons/"]
var allowedExt = ["gif","png","jpg","jpeg","svg"]
    const logoElement = document.getElementsByClassName("changelogo123");
/* .changelogo 요소가 없으면 종료 */
    if (logoElement.length === 0) {
        return;
    }
var logoTest = logoElement[0].innerHTML.toLowerCase();
//이미지 url이 주어진 조건에 맞는지 검사
var isSafeURL = allwedURLPattern.some( function(middleURL){
var reg = new RegExp("//" + middleURL)
return ( logoTest.match(reg) != null)
})
var isSafeExt = allowedExt.some( function(ext){
var reg = new RegExp("\." + ext + "$")
return ( logoTest.match(reg) != null)
})
// URL패턴과 확장자의 조건이 맞지 않으면 종료
    if ( !(isSafeURL && isSafeExt) ) {
return;
    }
    /* 로고 교체 */
    var orglogoElement = document.querySelector("#p-logo a");
    orglogoElement.style.backgroundImage = "url('" + logoElement[0].innerHTML + "')";
    /* 사이즈 교체 */
    var widthElement = document.querySelector(".changelogowidth");
widthElement.innerHTML = widthElement === null ? "160px" : widthElement.innerHTML;
var heightElement = document.querySelector(".changelogoheight");
heightElement.innerHTML = heightElement === null ? "160px" : heightElement.innerHTML;
orglogoElement.style.backgroundSize = widthElement.innerHTML + " " + heightElement.innerHTML;
}
$(logochange);
/* [[틀:로고 바꾸기]]용 함수 끝 */
/**
* [[백괴게임:댸문]]문서의 일부 링크를 낚시문서로 바꿔치기
* 원작성자: [[사용자:BANIP|BANIP]]
*/
$(function(){
var gate = document.getElementsByClassName("fakegate");
    if (gate[0] === undefined || gate[0] === null) {
    return;
    } else{
var targetLink = "https://libertygame.miraheze.org/wiki/"+gate[0].innerHTML;
$("#bodyContent a").attr("href",targetLink);
}
})
/* [[백괴게임:댸문]]문서의 일부 링크를 낚시문서로 바꿔치기 끝 */
/**
* pluginX Core
* pluginX 시스템이 제대로 돌아가게 해 줍니다.
* 작성자: [[사용자:Bd3076|Bd3076]]
*/
function pluginXCore() {
    var api = MediaWikiAPI();
    var ipUser = false;
if(mw.config.get("wgUserName") === null) ipUser = true;
    var script_list = [];
    var pluginExist = false;
    var neededPluginExist = false;
    var html_before;
    var jsonDoc = "사용자:" + mw.config.get("wgUserName") + "/pluginX.json";
    var jsonData = JSON.parse(api.getDocument(jsonDoc));
   
    /// 플러그인의 정보가 담긴 데이터를 만듭니다.
    var generateScriptData = function(_url, _name, _creator, _doc, _script, _revid){
    return {
    url: _url,
    name: _name,
    creator: _creator,
    doc: _doc,
    script: _script,
    revid: _revid
    };
    };
   
    /// 플러그인 목록을 만들어서 script_list[]에 담습니다.
    var getPluginList = function(){
    $(".c_pluginX").each(function() {
    pluginExist = true;
    var url = $(this).attr('data-url');
    var name = $(this).attr('data-name');
    var creator = $(this).attr('data-creator');
    var doc = $(this).attr('data-doc');
    var revid = $(this).attr('data-revid');
   
    var script = api.getDocument(doc);
   
    script_list.push(generateScriptData(url, name, creator, doc, script, revid));
   
    if(jsonData[doc] === undefined || jsonData[doc] !== revid){
    console.log(name);
    neededPluginExist = true;
    }
    });
    };
   
    /// 플러그인을 실행합니다.
    var executePlugins = function(){
    script_list.forEach(function(data){
    var link = data.url;
    var revid = data.revid;
    var doc = data.doc;
   
    if(neededPluginExist){
    jsonData[doc] = revid;
    }
   
    $.getScript(link);
    });
   
    ///자동 인증된 사용자가 플러그인을 실행할 경우 json을 갱신합니다.
    var userGroups = mw.config.get('wgUserGroups');
        var autocheck = 0;
        if (userGroups) {
        for (var i = 0; i < userGroups.length; i++) {
        if (userGroups[i] === 'autoconfirmed') {
        autocheck++;
        }
        }
        }
    if(neededPluginExist && !(autocheck == 0) ){
    api.changeDocument(jsonDoc, "pluginX - 새로운 플러그인", JSON.stringify(jsonData));
    }
    };
   
    /// 플러그인을 실행하지 않습니다.
    var doNotExecutePlugins = function(){
    document.getElementById('mw-content-text').innerHTML = html_before;
    };
   
    /// 알림 창을 만듭니다.
    var showWindow = function(){
    html_before = document.getElementById('mw-content-text').innerHTML;
    $('#mw-content-text').html(api.readDocument("틀:PluginX/setup"));
    var script = "";
   
    script_list.forEach(function(data){
    var addingCode;
    addingCode = '<div class="px-code"><pre>';
    addingCode = addingCode.concat(((data.script.replace(/&/g, '&amp;')).replace(/</g, '&lt;')).replace(/>/g, '&gt;'));
    addingCode = addingCode.concat('</pre> </div> <div class="px-codeinfo"> <ul> <li> 플러그인 이름: ');
    addingCode = addingCode.concat(data.name);
    addingCode = addingCode.concat('</li> <li> 플러그인 제작자: ');
    addingCode = addingCode.concat(data.creator);
    addingCode = addingCode.concat('</li> </ul> </div>');
   
    // 위험 코드 탐지 시작
    var pattern;
    var nscode = data.script.replace(/\r?\n|\r/g, ' ');
   
    // 패턴 1. document.innerHTML 사용 (위험도: 심각)
    pattern = new RegExp("^.*document *\. *innerHTML.*$");
   
    if(pattern.test(nscode)){
    addingCode = addingCode.concat('<div class="px-critical">이 플러그인은 문서 열람 시 지장을 줄 수 있습니다.<br>플러그인 제작자를 신뢰할 수 있는 경우에만 실행하시기 바랍니다.</div>');
    }
   
    // 패턴 2. document.write 사용 (위험도: 심각)
    pattern = new RegExp("^.*document *\. *write.*$");
   
    if(pattern.test(nscode)){
    addingCode = addingCode.concat('<div class="px-critical">이 플러그인은 문서 내용을 왜곡시킬 수 있습니다.<br>플러그인 제작자를 신뢰할 수 있는 경우에만 실행하시기 바랍니다.</div>');
    }
   
    // 패턴 3. "wgUserName" 사용 (위험도: 안내)
    pattern = new RegExp('^.*"wgUserName".*$');
   
    if(pattern.test(nscode)){
    addingCode = addingCode.concat('<div class="px-notice">이 플러그인은 당신의 사용자 이름을 수집합니다.<br>이를 원치 않으시면 플러그인을 실행하지 마시기 바랍니다.</div>');
    }
   
    //패턴 4. MediaWikiAPI.changeDocument 사용(위험도: 경고)
    pattern = new RegExp('^.*MediaWikiAPI.*changeDocument.*$');
   
    if(pattern.test(nscode)){
    addingCode = addingCode.concat('<div class="px-warning">이 플러그인은 다른 문서를 편집합니다.<br>이 게임이 계정 생성형 게임일 가능성이 높습니다.<br>플러그인 제작자를 신뢰할 수 있는 경우에만 실행하시기 바랍니다.</div>');
    }
   
    script += addingCode;
    });
   
    document.getElementById('px-script').innerHTML = script;
   
$('#px-button').on('click', executePlugins);
$('#px-button2').on('click', doNotExecutePlugins);
    };
   
    getPluginList();
   
    if(pluginExist === false) return;
   
    if(neededPluginExist === false){
    executePlugins();
    return;
    }
    else{
    showWindow();
    return;
    }
}
$(pluginXCore);
/* pluginX Core 끝 */
/** 플러그인 inputform
* 완전한 입력기를 구현합니다. (베타)
* 작성자 : [[사용자:Gustmd7410|Gustmd7410]]
*/
function plugin_inputform(){
  // 이부분에 코드 입력 //
mw.loader.using('oojs-ui-core').done(function () {
    function toBool(value) {
        switch (value) {
            case undefined: return false;
            case '': return true;
        }
    }
    function toArray(value) {
        if (value)
            return value.split(' ');
        else
            return undefined;
    }
    function InpTable(table) {
        this["case"] = {};
        this["default"] = Object.assign({
            prefix: '',
            value: undefined,
            suffix: '',
            replace: [],
            sub: [0]
        }, table["default"]);
        if (table["case"]) {
            for (var value in table["case"]) {
                this["case"][value] = Object.assign({}, this["default"], { value: this["default"].value || value }, table["case"][value]);
            }
        }
    }
    $('.input-form').each(function () {
        var container = this;
        $(this).html(new $('<form />', {
            "class": $(this).data('class'),
            id: $(this).data('id'),
            style: $(this).data('style'),
            'accept-charset': 'UTF-8',
            autocomplete: toBool($(this).data('autocomplete')),
            novalidate: toBool($(this).data('novalidate')),
            html: $(this).html()
        }));
        $(this).children('form').submit(function (event) {
            event.preventDefault();
            var action = new URL('/w/index.php', location);
            if (toBool($(container).data('pass')))
                action.search = location.search;
            if ($(container).data('get'))
                new URLSearchParams($(container).data('get')).forEach(function (value, key) {
                    action.searchParams.set(key, value);
                });
            action.searchParams.set('title', $(container).data('title'));
            $(this).children('.input-field').each(function () {
                if (typeof ($(this).data('table')) == 'object') {
                    var name = $(this).data('name');
                    var rawval = $(this).find('input').val();
                    var table = new InpTable($(this).data('table'));
                    var cvttbl = table["case"][rawval] || table["default"];
                    var cvtval = (cvttbl.value || rawval).slice(cvttbl.sub[0], cvttbl.sub[1]);
                    cvttbl.replace.forEach(function (reparr) {
                        var regex = reparr[0].substr(1).split('/');
                        regex.pop();
                        regex = regex.join('/');
                        var flag = reparr[0].substr(1).split('/').reverse()[0];
                        cvtval = cvtval.replace(new RegExp(regex, flag), reparr[1]);
                    });
                    action.searchParams.set(name, cvttbl.prefix + cvtval + cvttbl.suffix);
                }
                else
                    action.searchParams.set($(this).data('name'), $(this).find('input').val());
            });
            location.href = action.href;
        });
    });
    $('.input-field').each(function () {
        $(this).html(new OO.ui.TextInputWidget({
            accessKey: $(this).data('accessKey'),
            autocomplete: toBool($(this).data('autocomplete')),
            autofocus: toBool($(this).data('autofocus')),
            classes: toArray($(this).data('classes')),
            disabled: toBool($(this).data('disabled')),
            flags: toArray($(this).data('flags')),
            icon: $(this).data('icon'),
            iconTitle: $(this).data('iconTitle'),
            id: $(this).data('id'),
            indicator: $(this).data('indicator'),
            indicatorTitle: $(this).data('indicatorTitle'),
            inputId: $(this).data('inputId'),
            maxLength: Number($(this).data('maxLength')),
            name: $(this).data('name'),
            placeholder: $(this).data('placeholder'),
            readOnly: toBool($(this).data('readOnly')),
            required: toBool($(this).data('required')),
            spellcheck: toBool($(this).data('spellcheck')),
            tabIndex: Number($(this).data('tabIndex')),
            text: $(this).data('text'),
            title: $(this).data('title'),
            type: $(this).data('type'),
        validate: (function(container) {
            if ($(container).data('validatetype') == 'RegExp') {
                var value = $(container).data('validate').substr(1).split('/');
                return RegExp(value[0], value[1]);
            }
            else
                return $(container).data('validate');
        })(this),
            value: this.dataset.value || ''
        }).$element);
       
        if(toBool($(this).data('inline'))) $(this).find('*').css({
            display: 'inline',
            width: 'auto'
        });
    });
    $('.input-button').each(function () {
        $(this).html(new OO.ui.ButtonInputWidget({
            accessKey: $(this).data('accessKey'),
            classes: toArray($(this).data('classes')),
            disabled: toBool($(this).data('disabled')),
            flags: toArray($(this).data('flags')),
            framed: toBool($(this).data('framed')),
            icon: $(this).data('icon'),
            iconTitle: $(this).data('iconTitle'),
            id: $(this).data('id'),
            indicator: $(this).data('indicator'),
            indicatorTitle: $(this).data('indicatorTitle'),
            inputId: $(this).data('inputId'),
            label: $(this).data('label'),
            name: $(this).data('name'),
            tabIndex: Number($(this).data('tabIndex')),
            text: $(this).data('text'),
            title: $(this).data('title'),
            type: $(this).data('type'),
            value: $(this).data('value')
        }).$element);
    });
    noPlugin('input');
});
}
$( plugin_inputform );
/* inputform 끝 */
/** [[틀:SCGI]]에서 사용하는 링크 리다이렉트 함수
* class="scgi-use"
* 작성자: [[사용자:Gustmd7410|Gustmd7410]]
**/
$(function useSCGI() {
if(!URLSearchParams) return;
$('.scgi-use a').each(function() {
var href = new URL(this.href);
var params = new URLSearchParams(location.search);
if(
location.host === href.host && (
location.pathname === '/w/index.php' && params.get('title') ||
location.pathname.startsWith('/wiki/') && location.pathname.replace('/wiki/', '')
) === (
href.pathname === '/w/index.php' && params.searchParams.get('title') ||
href.pathname.startsWith('/wiki/') && href.pathname.replace('/wiki/', '')
) && params.get('action') === href.searchParams.get('action')
) $(this).click(function(event) {
event.preventDefault();
location.replace(event.currentTarget.href);
});
});
});
/* [[틀:SCGI]]에서 사용하는 링크 리다이렉트 함수 끝 */


/** 편집 저장시 다른 문서나 CGI로 넘겨주기
/** 편집 저장시 다른 문서나 CGI로 넘겨주기
1,528번째 줄: 141번째 줄:


/* 편집 저장시 다른 문서나 CGI로 넘겨주기 끝 */
/* 편집 저장시 다른 문서나 CGI로 넘겨주기 끝 */
/** JSON 편집을 편리하게 해 주는 기능.
*  [[틀:JSON수정]]을 위한 플러그인입니다.
*  작성자: [[사:Bd3076|Bd3076]]
*/
function uncy_jsonEdit(){
var mp = new Map();
var api = MediaWikiAPI();
$('.uncy-jsonedit').each(function() {
    var jsonDoc = $(this).attr("data-title");
    if (jsonDoc.indexOf("/pluginX.json") !== -1) {
    console.log("사용자의 pluginX JSON은 안돼요!");
    return;
    }
    var jsonData;
    if(mp.get(jsonDoc) === undefined){
    jsonData = JSON.parse(api.getDocument(jsonDoc));
    }
    else{
    jsonData = JSON.parse(mp.get(jsonDoc));
    }
    var variable = $(this).attr("data-var");
    var value = $(this).attr("data-val");
    var reset = $(this).attr("data-reset");
   
    if(reset === "1") jsonData = {};
    else jsonData[variable] = value;
   
    mp.set(jsonDoc, JSON.stringify(jsonData));
    console.log(jsonDoc);
    console.log(JSON.stringify(jsonData));
});
mp.forEach(function(value, key) {
if(key === undefined){
console.log("error: document name is undefined");
return;
}
if(value === undefined){
console.log("error: variable or value is wrong");
return;
}
api.changeDocument(key, "JSON 데이터 수정", value, 1, 1);
mw.loader.using( ['mediawiki.notify','mediawiki.Title'] ).then( function () {
    mw.notify('JSON 데이터가 수정되었습니다.');
});
});
}
$(uncy_jsonEdit);
/* JSON 편집을 편리하게 해 주는 기능 끝 */




1,665번째 줄: 225번째 줄:
/* [[틀:자동저장]]용 문서 미리 비워놓기 끝 */
/* [[틀:자동저장]]용 문서 미리 비워놓기 끝 */


/** 진동 구현
* 작성자: 사용자:아라
*/
/*
function Vibration(duration) {
    if (!document.getElementById('vibrate')) return;
    if (!duration) duration = 100;
    if (duration > 1000) duration = 1000;
    navigator.vibrate(duration);
}
$(function() {
Vibration(100);
});
*/
/* 진동 구현 끝 */


/** 게임 컨트롤러 진동 구현
/** mediawiki api를 통해 간단하게 문서들을 수집, 변경하는 함수.
  * 작성자: 사용자:아라 (사용자 공대여자 소스 참조)
  * @deprecated
* 이 기능은 사용을 권장하지 않습니다. 대신 mw.Api를 사용해 주세요. (참조: https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api)
* 동기 XHR은 정보를 가져오는 동안 페이지를 멈춰 현저한 성능 저하를 야기하여 WHATWG 표준에서 제외되었고, 이에 따라 최신 브라우저에서 작동하지 않게 되었습니다.
* MediaWikiAPI는 동기 XHR 기능에 의존하도록 설계되었고, 이 기능을 사용하는 모든 기능들은 작동을 보장할 수 없게 되었습니다.
*
* 플러그인 코어에서 사용하기 위해 만들었습니다.
* 원작성자: [[사용자:BANIP|BANIP]], 수정자: [[사용자:Bd3076|Bd3076]]
* 사용방법
*: var api = MediaWikiAPI(); .changeDocument()
*: api.changeDocument(변경할 문서의 타이틀, 편집 요약, 변경할 문서의 내용) => 문서의 내용을 변경합니다.
*: api.addDocument(변경할 문서의 타이틀, 편집 요약, 추가할 문서의 내용) => 문서에 새로운 내용을 추가합니다.
*: api.getDocument(가져올 문서의 타이틀) => 문서의 모든 텍스트를 읽어옵니다.
*: api.readDocument(가져올 문서의 타이틀) => 문서의 모든 텍스트를 jquery 객체로 읽어옵니다.
* 영 좋지 않은 목적으로 사용 하면 안드로메다 경찰관이 잡아간다!
  */
  */
/*
function GamepadVibration(idx, duration) {
    if (!document.getElementById('vibrate')) return;
    var gamepads = navigator.getGamepads();
    if (!idx) idx = 0;
    if (!gamepads[idx]) return;
    var pad = gamepads[idx];
    if (!duration) duration = 100;
    if (duration > 1000) duration = 1000;
    pad.vibrationActuator.playEffect(pad.vibrationActuator.type, {
        startDelay: 0,
        duration: duration,
        weakMagnitude: 0.5,
        strongMagnitude: 1
    });
}
$(function() {
GamepadVibration(0, 100);
});
*/
/* 게임 컨트롤러 진동 구현 끝 */


/** TTS 지원
function MediaWikiAPI() {
* class="speech" (lang="") (data-pitch="") (data-rate="") (data-volume="")
console.warn('권장하지 않는 MediaWikiAPI를 사용하고 있습니다. 대신 mw.Api를 사용해 주세요.');
* 제작자: [[사용자:hsl0]]
**/
/*
var voiceSettings = {};
voiceSettings.default = {
voice: null,
pitch: 1,
rate: 1,
volume: 1
};
function speakSpeech() {
var ssu, setting;
if(!('notts' in geturlSearch() || window.disableTTS)) Array.from(document.getElementsByClassName('speech')).forEach(function(elem) {
    var token;
ssu = new SpeechSynthesisUtterance(elem.innerText);
    var getToken = function() {
        if (token !== undefined) return token;
ssu.lang = elem.lang;
        $.ajax({
setting = Object.assign({}, voiceSettings.default, voiceSettings[ssu.lang]);
            url: "/api.php?action=query&meta=tokens", // Note: URL은 서버 디렉토리 설정에 따라 바꾸어야 합니다.
if(setting.voice) ssu.voice = setting.voice;
            success: function(v, i) {
if(!isNaN(elem.dataset.pitch)) ssu.pitch = setting.pitch * elem.dataset.pitch;
                var datas = JSON.parse($(v).find("pre").text());
if(!isNaN(elem.dataset.rate)) ssu.rate = setting.rate * elem.dataset.rate;
                token = datas.query.tokens.csrftoken;
if(!isNaN(elem.dataset.volume)) ssu.volume = setting.volume * elem.dataset.volume;
            },
            async: false
speechSynthesis.speak(ssu);
        });
});
        return token;
    };
 
    function changeDocument(title, summary, content, isUnReload, minor) {
    mw.loader.using( ['mediawiki.util','mediawiki.Title'] ).then( function () {
    $.ajax({
            url: mw.util.wikiScript("api"),
            data: {
                format: 'json',
                action: 'edit',
                title: title,
                summary: summary,
                text: content,
                minor: minor,
                token: getToken(),
            },
            dataType: 'json',
            type: 'POST',
            success: function(data) {
                if (data && data.edit && data.edit.result == 'Success') {
                    if (!isUnReload) window.location.reload(); // reload page if edit was successful
                } else if (data && data.error) {
                    alert('Error: API returned error code "' + data.error.code + '": ' + data.error.info);
                } else {
                    alert('Error: Unknown result from API.');
                }
            },
            error: function(xhr) {
                alert('Error: Request failed.');
            }
        });
} );
    }
 
    function addDocument(title, summary, content, isUnReload, minor) {
        originContent = getDocument(title);
        changeDocument(title, summary, originContent + content, isUnReload, minor);
    }
 
    function getDocument(title) {
        function entityDecode(doc) {
            return $('<p></p>').html(doc).text();
        }
 
        var originContent;
        $.ajax({
            url: "/" + wgScriptPath + "?title=" + title + "&action=edit",
            success: function ajaxSucess(data) {
                originContent = $(data).find("textarea").html();
            },
            async: false
        });
        return entityDecode(originContent);
    }
 
    function readDocument(title) {
        var doc;
        $.ajax({
            url: "/" + wgScriptPath + "/" + title,
            success: function ajaxSucess(data) {
                doc = $(data).find("#mw-content-text");
            },
            async: false
        });
        return doc;
    }
 
 
    return {
        getToken: getToken,
        changeDocument: changeDocument,
        addDocument: addDocument,
        getDocument: getDocument,
        readDocument: readDocument,
    };
}
}
$(speakSpeech);
*/
/* TTS 끝 */
/**
* punycode.js - 퓨니코드 처리 라이브러리
* DB2에서 미디어위키 옵션 저장소 키의 문자열 제한 우회를 위해 사용중
* 제작자: bestiejs - https://github.com/bestiejs/punycode.js
* 라이선스: MIT 라이선스
* 출처: CDNJS - https://cdnjs.cloudflare.com/ajax/libs/punycode/1.4.1/punycode.min.js
**/
!function(e){function o(e){throw new RangeError(T[e])}function n(e,o){for(var n=e.length,r=[];n--;)r[n]=o(e[n]);return r}function r(e,o){var r=e.split("@"),t="";r.length>1&&(t=r[0]+"@",e=r[1]),e=e.replace(S,".");var u=e.split("."),i=n(u,o).join(".");return t+i}function t(e){for(var o,n,r=[],t=0,u=e.length;u>t;)o=e.charCodeAt(t++),o>=55296&&56319>=o&&u>t?(n=e.charCodeAt(t++),56320==(64512&n)?r.push(((1023&o)<<10)+(1023&n)+65536):(r.push(o),t--)):r.push(o);return r}function u(e){return n(e,function(e){var o="";return e>65535&&(e-=65536,o+=P(e>>>10&1023|55296),e=56320|1023&e),o+=P(e)}).join("")}function i(e){return 10>e-48?e-22:26>e-65?e-65:26>e-97?e-97:b}function f(e,o){return e+22+75*(26>e)-((0!=o)<<5)}function c(e,o,n){var r=0;for(e=n?M(e/j):e>>1,e+=M(e/o);e>L*C>>1;r+=b)e=M(e/L);return M(r+(L+1)*e/(e+m))}function l(e){var n,r,t,f,l,s,d,a,p,h,v=[],g=e.length,w=0,m=I,j=A;for(r=e.lastIndexOf(E),0>r&&(r=0),t=0;r>t;++t)e.charCodeAt(t)>=128&&o("not-basic"),v.push(e.charCodeAt(t));for(f=r>0?r+1:0;g>f;){for(l=w,s=1,d=b;f>=g&&o("invalid-input"),a=i(e.charCodeAt(f++)),(a>=b||a>M((x-w)/s))&&o("overflow"),w+=a*s,p=j>=d?y:d>=j+C?C:d-j,!(p>a);d+=b)h=b-p,s>M(x/h)&&o("overflow"),s*=h;n=v.length+1,j=c(w-l,n,0==l),M(w/n)>x-m&&o("overflow"),m+=M(w/n),w%=n,v.splice(w++,0,m)}return u(v)}function s(e){var n,r,u,i,l,s,d,a,p,h,v,g,w,m,j,F=[];for(e=t(e),g=e.length,n=I,r=0,l=A,s=0;g>s;++s)v=e[s],128>v&&F.push(P(v));for(u=i=F.length,i&&F.push(E);g>u;){for(d=x,s=0;g>s;++s)v=e[s],v>=n&&d>v&&(d=v);for(w=u+1,d-n>M((x-r)/w)&&o("overflow"),r+=(d-n)*w,n=d,s=0;g>s;++s)if(v=e[s],n>v&&++r>x&&o("overflow"),v==n){for(a=r,p=b;h=l>=p?y:p>=l+C?C:p-l,!(h>a);p+=b)j=a-h,m=b-h,F.push(P(f(h+j%m,0))),a=M(j/m);F.push(P(f(a,0))),l=c(r,w,u==i),r=0,++u}++r,++n}return F.join("")}function d(e){return r(e,function(e){return F.test(e)?l(e.slice(4).toLowerCase()):e})}function a(e){return r(e,function(e){return O.test(e)?"xn--"+s(e):e})}var p="object"==typeof exports&&exports&&!exports.nodeType&&exports,h="object"==typeof module&&module&&!module.nodeType&&module,v="object"==typeof global&&global;v.global!==v&&v.window!==v&&v.self!==v||(e=v);var g,w,x=2147483647,b=36,y=1,C=26,m=38,j=700,A=72,I=128,E="-",F=/^xn--/,O=/[^\x20-\x7E]/,S=/[\x2E\u3002\uFF0E\uFF61]/g,T={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},L=b-y,M=Math.floor,P=String.fromCharCode;if(g={version:"1.4.1",ucs2:{decode:t,encode:u},decode:l,encode:s,toASCII:a,toUnicode:d},"function"==typeof define&&"object"==typeof define.amd&&define.amd)define("punycode",function(){return g});else if(p&&h)if(module.exports==p)h.exports=g;else for(w in g)g.hasOwnProperty(w)&&(p[w]=g[w]);else e.punycode=g}(this);
//# sourceMappingURL=./punycode.min.js.map
/* punycode.js 끝 */


/** @function fetchScript
/** @function fetchScript
1,772번째 줄: 357번째 줄:
     });
     });
} : $.getScript;
} : $.getScript;
 
/**
/** [[:DB2]]
* API 에러가 반환될 경우 알려주는 함수
  * 제작자: [[사용자:hsl0]]
* 저작자: [[사용자:hsl0|hsl0]]
**/
function notifyApiError(msg, option, code, object) {
option = option || {};
mw.notification.notify(
        code === 'http'?
            $('<span />')
                .append($('<p />', {class: 'api-errmsg'}).text(object.xhr.responseText).html(option.additionalMessage || ''))
                .append($('<code />', {class: 'api-errcode'}).text('HTTP ' + object.xhr.status)) :
            $('<span />')
                .append($('<p />', {class: 'api-errmsg'}).text(object.error.info).html(option.additionalMessage || ''))
                .append($('<code />', {class: 'api-errcode'}).text(code)),
        {
            title: msg,
            type: 'error',
            tag: option.tag,
            autoHideSeconds: 'long'
        }
    );
}
/** 링크경고
* 자바스크립트로 링크에 경고를 넣을 수 있습니다.
  * 제작자: [[사용자:hsl0|hsl0]]
**/
**/
mw.loader.using([
function linkWarn(element, msg, msgClass) {
    'mediawiki.notification',
return $(element)
    'oojs-ui-core'
.addClass('linkwarn tooltip')
]);
.append($('<span class="tooltip-msg" />').append(msg).addClass(msgClass || 'messagebox'));
function enableDB2() {
}
    var title = mw.config.get('wgPageName').split('/')[0].split(':');
    title = title[0].replace(/talk|토론/gi, '') + ':' + title[1];
    var noti;
    var currentUrl = new mw.Title(mw.config.get('wgPageName')).getUrl(geturlSearch());


    /* option key 인코딩
/**
        퓨니코드 + url인코딩
* [[리버티게임:오락실/2023년_8월#사이드바 '임의의 게임으로' 기능 관련]]
        % = _
* --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 8월 14일 (월) 10:36 (KST)
        _ = __
*/
    */
$(function(){
    function encode(key) {
    var triggered = false;
        return encodeURIComponent(punycode.toASCII(key))
    var $linkwrapper = $("#n-randompage, .move-randompage").find("a");
        .replace(/\./g, '%2E')
//[[틀:임의_게임]] 구현, 사이드바 임의게임으로 링크 바인딩
        .replace(/!/g, '%21')
$linkwrapper.on("click",function(e){
        .replace(/~/g, '%7E')
var category = $(this).closest(".move-randompage").data("category") || undefined
        .replace(/\*/g, '%2A')
e.preventDefault();
        .replace(/'/g, '%27')
         if(triggered) return;
        .replace(/\(/g, '%28')
         triggered = true;
        .replace(/\)/g, '%29')
        .replace(/_/g, '__')
         .replace(/%/g, '_');
    }
    function decode(key) {
         return punycode.toUnicode(decodeURIComponent(key.replace(/_(?=[a-zA-Z0-9]{2})/g, '%').replace(/__/g, '_')));
    }


    function parseJSON(json) {
(new mw.Api()).get({
        try {
    action: 'parse',
            return JSON.parse(json);
    page: '리버티게임:임의 게임',
        } catch(e) {
    formatversion: 2,
            return;
    category:category
        }
}).then(function(res){
    }
    var page = $(res.parse.text).find(".redirect-random-page").text().trim();
    location.href = mw.util.getUrl(page);
}).catch(function(){
    location.href = mw.util.getUrl("리버티게임:임의 게임",{category:category});
});
}).attr("rel","nofollow");


    // hybridStorage 서브셋 생성
//[[리버티게임:임의_게임]] 구현
    window.setStoragePrefix = function(storage, prefix, except, needEncode) {
if($("#content .redirect-random-page").length){
        if(mw.user.isAnon()) needEncode = false;
    history.replaceState(null, null, mw.util.getUrl($("#content .redirect-random-page").text().trim()));
    location.reload();
}
});


        var spp = new Proxy(storage, {
/**
            get: function(target, prop, receiver) {
* 리버티게임 인기 게임 순위 정렬
                function keys() {
* ver 1.2.1 --{{사용자:Senouis/서명}} 2024년 9월 15일 () 16:43 (KST)
                    return Object.keys(target).filter(function(key) {
*/
                        return key.startsWith(prefix);
$(function (){
                    });
var sectionRatings = document.getElementsByClassName("section-ratings");
                }
var sectionRatings_param = "4";
               
if (sectionRatings.length === 0) return;
                return Reflect.get(Object.assign({
if (document.getElementById("sectionRatings-parameter")) sectionRatings_param = document.getElementById("sectionRatings-parameter").innerText;
                    length: (prop === 'length') && keys().length,
for (var i in sectionRatings){
                    getItem: function getItem(key) {
var param1 = sectionRatings.item(i).innerText;
                        return target.getItem(prefix + (needEncode? encode(key) : key));
fetch("https://libertyga.me/rest.php/sectionratings/v0/ratings/"+param1+"/" + sectionRatings_param).then(function (result){return result.json();}).then(function (result){
                    },
if (result.result !== "SUCCESS") return;
                    key: function key(index) {
if (!result.category) return;
                        return decode(keys()[index].slice(prefix.length));
var sectionRatings = document.getElementsByClassName("section-ratings");
                    },
if (Object.keys(result.gameList).length === 0){
                    removeItem: function removeItem(key) {
for (var k in sectionRatings){
                        return target.removeItem(prefix + (needEncode? encode(key) : key)).then(function() {
if (sectionRatings.item(k).innerText === result.category){
                            return spp;
sectionRatings.item(k).innerText = "\n\n\n\n\n\n";
                        });
break;
                    },
}
                    setItem: function setItem(key, value) {
}
                        return target.setItem(prefix + (needEncode? encode(key) : key), value).then(function() {
return;
                            return spp;
}
                        });
var tempElement = document.createElement("div");
                    }
tempElement.innerHTML = result.parseResult;
                }, except), prop, receiver) || target.getItem(prefix + (needEncode? encode(prop) : prop));
for (var j in sectionRatings){
            },
if (sectionRatings.item(j).innerText === result.category){
            set: function(target, prop, value) {
sectionRatings.item(j).innerText = "";
                return target.setItem(prefix + (needEncode? encode(prop) : prop), value);
var elemlist = tempElement.querySelectorAll(".gamecard");
            },
for (var idx in elemlist){
            deleteProperty: function(target, prop) {
try{
                return target.removeItem(prefix + (needEncode? encode(prop) : prop));
var elem = elemlist.item(idx);
            },
sectionRatings.item(j).appendChild(elem);
            has: function(target, prop) {
} catch (e) {
                Reflect.has(target, prefix + (needEncode? encode(prop) : prop));
continue;
            },
}
            ownKeys: function(target) {
}
                return Reflect.ownKeys(target).filter(function(key) {
break; // 작업 종료
                    return key.startsWith(prefix);
}
                }).map(function(key) {
}
                    return decode(key.slice(prefix.length));
}).catch(function(e){console.log(e);});
                });
}
            }
});
        });
        return spp;
    };


    /*
/**
        anon = localStorage[*]
* DisucussionTools가 알림 상자 틀을 망가뜨리는 문제 해결을 위한 스크립트(작동 중지)
        user = mw.user.options[userjs-*]
* --[[사용자:Senouis|Senouis]] ([[사용자토론:Senouis|토론]]) 2024년 8월 30일 () 11:47 (KST)
    */
*/
    window.hybridStorage = (function() {
        var action;
        var api = new mw.Api();
        var storage, action;
        var saveOption = (function() {
            var options = {};
            var deferred = new $.Deferred();
            var timeout = null;
           
            return function saveOption(key, value) {
                if(timeout) clearTimeout(timeout);
                options[key] = value;
                timeout = setTimeout(function() {
                    api.saveOptions(options).then(deferred.resolve, deferred.reject);
                   
                    options = {};
                    timeout = null;
                    deferred = new $.Deferred();
                }, 100);
                return deferred.promise();
            };
        })();
        if(mw.user.isAnon()) {
            storage = new Proxy(localStorage, {
                get: function(target, prop, receiver) {
                    var value = Reflect.get({
                        length: target.length,
                        getItem: target.getItem,
                        key: target.key,
                        removeItem: function removeItem(key) {
                            return Promise.resolve(target.removeItem(key));
                        },
                        setItem: function setItem(key, value) {
                            return Promise.resolve(target.setItem(key, value));
                        },
                        refresh: function refresh() {
                            return Promise.resolve(storage);
                        },
                        needRefresh: false
                    }, prop, receiver) || target.getItem(prop);
                    return (value === null)? undefined : value;
                },
                set: function(target, prop, value, receiver) {
                    return Promise.resolve(target.setItem(prop, value));
                },
                deleteProperty: function(target, prop) {
                    return Promise.resolve(target.removeItem(prop));
                }
            });
        } else {
            action = {
                removeItem: function removeItem(key) {
                    if(key) return saveOption("userjs-" + key, null);
                    else throw new TypeError("Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present.");
                },
                setItem: function setItem(key, value) {
                    if(key) return saveOption("userjs-" + key, value);
                    else throw new TypeError("Failed to execute 'removeItem' on 'Storage': 1 argument required, but only 0 present.");
                },
                refresh: (function() {
                    var deferred = new $.Deferred();
                    var timeout = null;
                   
                    return function refresh() {
                        if(timeout) clearTimeout(timeout);
                        timeout = setTimeout(function() {
                            api.get({
                                action: 'query',
                                meta: 'userinfo',
                                uiprop: 'options'
                            }, {
                                cache: false
                            }).then(function(response) {
                                mw.user.options.values = response.query.userinfo.options;
                                return storage;
                            }).then(deferred.resolve, deferred.reject);
                           
                            timeout = null;
                            deferred = new $.Deferred();
                        }, 100);
                        return deferred.promise();
                    };
                })()
            };
            storage = new Proxy(mw.user.options, {
                get: function(target, prop, receiver) {
                    function keys() {
                        return Object.keys(target.values).filter(function(key) {
                            return key.startsWith('userjs-');
                        });
                    }
                   
                    return Reflect.get({
                        length: prop === 'length' && keys().length,
                        getItem: function getItem(key) {
                            if(key) return target.get("userjs-" + key);
                            else throw new TypeError("Failed to execute 'getItem' on 'Storage': 1 argument required, but only 0 present.");
                        },
                        key: function key(index) {
                            return keys()[index].slice(7);
                        },
                        removeItem: function removeItem(key) {
                        if(!target.exists("userjs-" + key)) return Promise.resolve();
                            return action.removeItem(key).then(function() {
                            Reflect.deleteProperty(target.values, "userjs-" + key);
                            });
                        },
                        setItem: function setItem(key, value) {
                        if(target.get("userjs-" + key) === value) return Promise.resolve();
                            return action.setItem(key, value).then(function() {
                            target.set("userjs-" + key, value);
                            });
                        },
                        refresh: action.refresh,
                        needRefresh: true
                    }, prop, receiver) || Reflect.get(target.values, "userjs-" + prop, receiver);
                },
                set: function(target, prop, value, receiver) {
                if(Reflect.get(target.values, "userjs-" + prop, receiver) === value) return Promise.resolve();
                    return action.setItem(prop, value).then(function() {
                    Reflect.set(target.values, "userjs-" + prop, value, receiver);
                    });
                },
                deleteProperty: function(target, prop) {
                if(!Reflect.has(target.values, "userjs-" + prop)) return Promise.resolve();
                    return action.removeItem(prop).then(function() {
                    Reflect.deleteProperty(target.values, "userjs-" + prop);
                    });
                },
                has: function(target, prop) {
                    return Reflect.has(target.values, "userjs-" + prop);
                },
                ownKeys: function(target) {
                    return Reflect.ownKeys(target.values).filter(function(key) {
                        return key.startsWith("userjs-");
                    }).map(function(key) {
                        return key.slice(7);
                    });
                }
            });
        }
        return storage;
    })();
    // local + global 슈퍼셋 (hybridStorage[gamedb-*])
    var rootGameDB = setStoragePrefix(hybridStorage, 'gamedb-', {
        refresh: function() {
            return hybridStorage.refresh().then(function() {
                return rootGameDB;
            });
        },
        needRefresh: hybridStorage.needRefresh
    }, true);
    // 게임별로 할당되는 영역 (rootGameDB[{게임}/*])
    window.localGameDB = setStoragePrefix(rootGameDB, title + '/', {
        refresh: function() {
            return rootGameDB.refresh().then(function() {
                return localGameDB;
            });
        },
        needRefresh: rootGameDB.needRefresh
    });
    // 모든 게임이 공유하는 영역 (rootGameDB[#*])
    window.globalGameDB = setStoragePrefix(rootGameDB, '#', {
        refresh: function() {
            return rootGameDB.refresh().then(function() {
                return globalGameDB;
            });
        },
        needRefresh: rootGameDB.needRefresh
    });


    function DataChange(href) {
$(function (){
        this.params = geturlSearch(new URL(href, location));
var amboces = document.getElementsByClassName("template-ambox");
        this.local = {};
if (amboces.length === 0) return;
        this.global = {};
for (var i in amboces) {
        this.root = {};
    var problemistic = amboces.item(i).querySelector("div div span:first-child");
        this.refresh = false;
    if (problemistic.id.substring(0,2) === "c-") {
        this.paramChanged = false;
    problemistic.style.display = "none";
    }
    }
    DataChange.prototype.control = function control(element) {
}
        var base, key, storage, params, val, paramChanged;
});
        var data = element.dataset;
       
        /* 저장할 키
            local: 키 지정
            global: 전역 키 지정
            local global: 키 지정
            (없음): 기본 키
        */
        if('local' in data && 'global' in data) {
        throw new TypeError('전역키와 일반키가 동시에 지정되었습니다');
        } else if('local' in data) {
            storage = localGameDB;
            base = this.local;
            key = data.local;
        } else if('global' in data) {
            storage = globalGameDB;
            base = this.global;
            key = data.global;
        } else {
            storage = rootGameDB;
            base = this.root;
            key = title;
        }
       
        switch(data.action) {
            // 호환
            case '저장':
            case 'save':
                /*
                    create: 새 키를 생성할 때만 저장
                */
              if(!('create' in data && key in base) && location.search) base[key] = JSON.stringify(geturlSearch());
            break;


            case '로드':
/**
            case 'load':
* 일반 이름공간 내에 있는 특정 분류의 문서 갯수를 가져오는 API 요청
                /*
* v1.3--{{사용자:Senouis/서명}} 2024년 9월 19일 () 01:25 (KST)
                    safe: 파라미터가 있으면 불러오지 않음
*/
                    fill: 없는 파라미터만 불러옴
$(function () {
                */
var categorylist = document.getElementsByClassName("pagecount");
                if(!(location.search && 'safe' in data)) {
if (categorylist.length === 0) return;
                Object.assign(this.params, parseJSON(storage.getItem(key)), 'fill' in data && this.params);
var parameter = [];
                this.paramChanged = true;
for (var i in categorylist) {
                }
var param = categorylist.item(i).innerText; // 이름공간을 제외하고 공백을 언더바(_)로 바꾼 분류 이름(예: 철도_교통_게임)을 파라미터로 함
            break;
parameter.push(param); // namespace 0번(일반 이름공간) 내 분류 갯수를 세도록 파라미터를 삽입한다.
 
            // 기본
            case '호출':
            case 'get':
            /*
            else: 저장된 데이터가 없을 때의 대체 텍스트
            */
                if(key in storage || data.else) {
                this.params[data.arg] = storage.getItem(key) || data.else;
                this.paramChanged = true;
                }
            break;
 
            case '수정':
            case 'set':
                /*
                    create: 새 키를 생성할 때만 저장
                */
              if(!('create' in data && key in base)) base[key] = data.arg;
            break;
 
            case '삭제':
            case '제거':
            case 'del':
                base[key] = null;
            break;
 
            // JSON
            case 'JSON':
            case 'json':
                /*
                    reset: 데이터 초기화
                */
                params = this.params;
                val = JSON.stringify(new CGI2Parser({
                    get: function(args) {
                    var base = this;
                        if(typeof args === 'object') Object.pairs(args).forEach(function(pair) {
                            if(base[pair[1]]) {
                            params[pair[0]] = base[pair[1]];
                            paramChanged = true;
                            }
                        });
                        else Array.from(arguments).forEach(function(key) {
                            if(base[key]) {
                            params[key] = base[key];
                            paramChanged = true;
                            }
                        });
                    },
                    set: function(args) {
                    var base = this;
                        Object.pairs(args).forEach(function(pair) {
                            base[pair[0]] = pair[1];
                        });
                    },
                    del: function() {
                    var base = this;
                        Array.from(arguments).forEach(function(key) {
                            delete base[key];
                        });
                    },
            def: function(args) {
                    var base = this;
                        Object.pairs(args).forEach(function(pair) {
                            if(!(pair[0] in base)) base[pair[0]] = pair[1];
                        });
                    },
                    sav: function(args) {
                    var base = this;
                        if(typeof args === 'object') Object.pairs(args).forEach(function(pair) {
                            base[pair[0]] = params[pair[1]];
                        });
                        else Array.from(arguments).forEach(function(key) {
                            base[key] = params[key];
                        });
                    }
                }).parse(parseJSON('reset' in data? '' : storage.getItem(key)) || {}, '[' + data.arg + ']'));
                if(val.length > 2) base[key] = val;
                Object.assign(this.params, params);
                if(paramChanged) this.paramChanged = true;
            break;
 
            default:
                $(element).addClass('error').text(data.action? "'" + data.action + "'은(는) 올바른 동작이 아닙니다" : '올바른 동작을 입력하지 않았습니다');
        }
    };
 
    /**
    * DB 저장
    * @function
    * @param {DataChange} change
    */
    DataChange.prototype.save = function() {
        var key, promise;
        var yet = true;
        var promises = [];
 
        if(title in this.root) {
            promises.push(rootGameDB.setItem(title, this.root[title]));
        }
        for(key in this.local) {
            promises.push(localGameDB.setItem(key, this.local[key]));
        }
        for(key in this.global) {
            promises.push(globalGameDB.setItem(key, this.global[key]));
        }
       
        promise = $.when.apply(null, promises);
        promise.then(function() {
        yet = false;
        });
       
        if(promises.length && !mw.user.isAnon()) setTimeout(function() {
        if(yet) noti = mw.notification.notify('데이터를 저장하는 중입니다...', {
            autoHide: false,
            tag: 'gameDB',
            type: 'pending'
        });
    }, 10);
 
        return promise;
    }
 
function handleError(code, object) {
    mw.notification.notify(
            code === 'http'?
                $('<span />')
                    .append($('<p />', {class: 'gameDB-noti-errmsg'}).text(object.xhr.responseText))
                    .append($('<code />', {class: 'gameDB-noti-errcode'}).text('HTTP ' + object.xhr.status)) :
                $('<span />')
                    .append($('<p />', {class: 'gameDB-noti-errmsg'}).text(object.error.info))
                    .append($('<code />', {class: 'gameDB-noti-errcode'}).text(code)),
            {
                title: '데이터 저장에 실패하였습니다.',
                type: 'error',
                tag: 'gameDB'
            }
        );
}
}
 
fetch("https://libertyga.me/rest.php/sectionratings/v0/categorycounter/"+parameter.join("|")+"/0").then(function (result){return result.json();}).then(function (result) {
    // 즉시
var categorylist2 = document.getElementsByClassName("pagecount");
    (function() {
for (var i in result.count) {
        var instant = new DataChange(location.href);
for (var j in categorylist2){
 
if (categorylist2.item(j).innerText === result.category[i]){ // 파라미터와 result.category가 같으면 치환
        $('.gameDB-control').each(function() {
categorylist2.item(j).innerText = result.count[i] === null ? 0 : result.count[i];
            instant.control(this);
categorylist2.item(j).style.display = "initial";
        });
break;
 
}
        instant.save().then(function() {
}
            var url = new mw.Title(instant.params.title || mw.config.get('wgPageName')).getUrl(instant.params) + location.hash;
}
           
});
            if(currentUrl !== url && instant.paramChanged) location.href = url;
});
            else if(noti) noti.close();
        }, handleError);
    })();
 
    // 링크
    (function() {
        function process(link, controllers, change) {
            controllers.each(function() {
                change.control(this);
            });
           
            var url = new mw.Title(change.params.title || mw.config.get('wgPageName')).getUrl(change.params) + new URL(link.href).hash;
            if(change.paramChanged) link.href = url;
            else if(link.href === location.href) link.href = "";
        }
 
        $('.gameDB-container').not(':has(a, .gameDB-container)').each(function() {
            var href;
 
            /*
                clear: 기존 파라미터 넘겨주지 않음
            */
            if('clear' in this.dataset) {
                href = new URL(location.href);
                href.search = '';
                href = href.href;
            } else href = location.href;
 
            $(this).html($('<a />', {
                href: href
            }).text(this.innerText));
        });
       
        $('.gameDB-container a').each(function() {
            var change = new DataChange(this.href);
            var controllers = $($(this).parents('.gameDB-container').get().reverse());
 
            process(this, controllers, change);
           
            $(this).data('change', change);
            $(this).addClass('gameDB-link');
        });
 
        $('.gameDB-link').on('click', function handler(event) {
            var link = this;
 
            if(!('done' in this.dataset)) {
            event.preventDefault();
            event.stopImmediatePropagation();
            }
 
            $(this).data('change').save().then(function() {
                if(link.href !== location.href) {
                    link.dataset.done = '';
                    $(link).off('click', handler)[0].click();
                } else mw.notification.notify('데이터가 저장되었습니다.', {
                    tag: 'gameDB'
                });
            }, handleError);
        });
    })();
}
$(function() {
mw.loader.using([
    'mediawiki.notification',
    'oojs-ui-core'
]).then(enableDB2)['catch'](console.error);
})
/* [[틀:DB2]] 끝 */

2024년 9월 19일 (목) 01:39 판

/* -- 전역 상수 선언 -- */
// 미디어위키 폴더명 url 다뤄야되는 함수들에서 사용됨, 메인터넌스 거친 후 w 혹은 wiki로 변경 예정, 
var wgScriptPath = "index.php";
/* 이 자바스크립트 설정은 모든 문서, 모든 사용자에게 적용됩니다. */
/** 플러그인이 작동하지 않을 때 나타나는 내용
 * js: noPlugin('(이름)');
 * html: class="noplugin-(이름)"
 * 작성자: [[사용자:Gustmd7410|Gustmd7410]] */
 
function noPlugin(name) {
    $('.noplugin-' + name).each(function() {
        $(this).remove();
    });
}

// [[미디어위키:common.js]] 미작동시: class="noplugin"
$('.noplugin').each(function() {
    $(this).remove();
});

/* window.location.search를 객체 형태로 반환
 @param {object} location 획득할 로케이션 객체, 비어있으면 window.location을 참조
 원작성자: [[사용자:BANIP|BANIP]]
 현 편집자: [[사용자:hsl0|hsl0]]
*/

function geturlSearch(location) {
	if(!location) location = window.location;
	else if(typeof location === 'string') location = new URL(location);
    var result = {};
    if (location.search)
        location.search.substring(1).replace(/\+/g, ' ').split("&").map(function(v) {
            return v.split("=");
        }).forEach(function(v) {
            result[decodeURIComponent(v[0])] = decodeURIComponent(v[1]);
        });
    return result;
}


/* 객체형태로 된 SearchParam을 받아 string형태로 반환
 원작성자: [[사용자:BANIP|BANIP]]
*/
function searchParamToString(searchParamsObj){
	return "?" + Object.entries(searchParamsObj).map(function(v){
		return v.map(function(v) {
			return encodeURIComponent(v);
		}).join("=");
	}).join("&");
}

/** [[백괴게임:연습장]] 문서 내용 비우기
 * 작성자: [[사용자:*devunt]]
 */
$(function() {
    if (mw.config.get("wgPageName") != "리버티게임:연습장")
        return;

    if (document.URL.lastIndexOf("action=edit") != -1) {
        if (document.URL.lastIndexOf("fakeaction=clean") == -1)
            return;

        var dbindex = document.editform.wpTextbox1;
        dbindex.value = "<!-- 이 줄은 지우지 마세요 -->{{리버티게임:연습장/안내문}}[["+"분류:리버티게임 도움말]]";
        document.editform.wpSummary.value = "연습장 비움";
        document.editform.wpSave.click();
        return;
    }
});

/* userAgent */
/** source: http://www.gregoryvarghese.com/how-to-get-browser-name-and-version-via-javascript/ **/

function get_browser_info() {
    var ua = navigator.userAgent,
        tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
    if (/trident/i.test(M[1])) {
        tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
        return {
            name: 'IE ',
            version: (tem[1] || '')
        };
    }

    if (M[1] === 'Chrome') {
        tem = ua.match(/\bOPR\/(\d+)/);
        if (tem != null) {
            return {
                name: 'Opera',
                version: tem[1]
            };
        }
    }

    M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];

    if ((tem = ua.match(/version\/(\d+)/i)) != null) {
        M.splice(1, 1, tem[1]);
    }

    return {
        name: M[0],
        version: M[1]
    };

}


/** 편집 저장시 다른 문서나 CGI로 넘겨주기
 * ?action=edit&redirectquery=(params)
 * 작성자: [[사용자:Gustmd7410|Gustmd7410]]
**/
$(function() {
	// 현재 URL 파라미터
	var params;
	
	// URLSearchParams 호환시
	if(URLSearchParams) params = new URLSearchParams(location.search);
	// 비호환시 geturlSearch() 사용
	else {
		// Map 호환시
		if(Map) params = new Map(Object.entries(geturlSearch()));
		// 비호환시 mw.Map 사용
		else {
			params = new mw.Map();
			params.values = geturlSearch();
			params.has = params.exists;
		}
	}
	
	// 편집창에서 redirectquery 파라미터가 있을때
	if(params.has('redirectquery')) {
		// 편집 폼에 wpExtraQueryRedirect 파라미터 input 요소 추가
		$('#editform').append($('<input />', {
			type: 'hidden',
			name: 'wpExtraQueryRedirect',
			value: params.get('redirectquery')
		}));
	}
});

/* 편집 저장시 다른 문서나 CGI로 넘겨주기 끝 */


/** 기여 확인용 플러그인
 * 작성자: [[사:Bd3076|Bd3076]]
 */
function enoughEdit(){
	function compareEditCount(number, id1, id2){
		var editCount = mw.config.get('wgUserEditCount');
		if(editCount < number){
			document.getElementById(id1).style.display = "block";
		}
		else{
			document.getElementById(id2).style.display = "block";
		}
	}
	
	$('.editCompare').each(function(){
		var num = $(this).attr("data-num");
		var enough = $(this).attr("data-id1");
		var nenough = $(this).attr("data-id2");
		compareEditCount(num, enough, nenough);
	});
}
$(enoughEdit);

/* 기여 확인용 플러그인 끝 */

/** 상위 문서 링크 바꿔치기
 * id="setsub"
 * 작성자: [[사용자:Gustmd7410|Gustmd7410]]
**/
function changeContentSub() {
	var newsub = document.getElementById('setsub');
	if(newsub) {
		document.querySelector('#contentSub').innerHTML = newsub.innerHTML;
		newsub.remove();
	}
}
$(changeContentSub);
/* 상위 문서 링크 바꿔치기 끝 */

/** [[틀:자동저장]]용 문서 미리 비워놓기
 * 원출처: [[틀:자동저장/플러그인]]
 * 비 자동 인증된 사용자가 자동저장 겸용 문서에서 복붙을 할 때 
 * 문서를 덮어씌우지 않고 밑에 복붙을 하는 상황을 막기 위한 플러그인입니다.
 */
 
 function nonautosaveready() {
 	
 	/* autosave 편집모드가 아닐 경우 플러그인 종료 */
	var searchParams = geturlSearch(location);
	var isEditMode = searchParams.action === "edit";
	var isAutosaveMode = searchParams.autosave === "1";
	if (!(isEditMode && isAutosaveMode)) return "";
	
	/* 자동 저장하기에 안전한 네임스페이스가 아닌 경우 플러그인 종료 */
	var safeNameSpace = [""];
	var thisNamespaceNumber = mw.config.get("wgNamespaceNumber");
	var nameSpaceIds = mw.config.get("wgNamespaceIds");
	var isSafeNameSpace = safeNameSpace
    .map(function (namespace) { return nameSpaceIds[namespace]; })
    .some(function (nsNumber) { return nsNumber == thisNamespaceNumber; });
    if (!(isSafeNameSpace)) return "";
    
    /* 자동 인증된 사용자가 일 경우 플러그인 종료 */
    var userGroups = mw.config.get('wgUserGroups');
    var autocheck = 0;
    if (userGroups) {
    	for (var i = 0; i < userGroups.length; i++) {
    		if (userGroups[i] === 'autoconfirmed') {
    			autocheck++;
    		}
    	}
    }
    if (autocheck != 0) return "";
    
    /* 미리 비워놓기 */
    var savetemp = document.editform.wpTextbox1;
    savetemp.value = "";
    return;
}
$(nonautosaveready);
/* [[틀:자동저장]]용 문서 미리 비워놓기 끝 */


/** mediawiki api를 통해 간단하게 문서들을 수집, 변경하는 함수.
 * @deprecated
 * 이 기능은 사용을 권장하지 않습니다. 대신 mw.Api를 사용해 주세요. (참조: https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api)
 * 동기 XHR은 정보를 가져오는 동안 페이지를 멈춰 현저한 성능 저하를 야기하여 WHATWG 표준에서 제외되었고, 이에 따라 최신 브라우저에서 작동하지 않게 되었습니다.
 * MediaWikiAPI는 동기 XHR 기능에 의존하도록 설계되었고, 이 기능을 사용하는 모든 기능들은 작동을 보장할 수 없게 되었습니다.
 * 
 * 플러그인 코어에서 사용하기 위해 만들었습니다.
 * 원작성자: [[사용자:BANIP|BANIP]], 수정자: [[사용자:Bd3076|Bd3076]]
 * 사용방법 
 *: var api = MediaWikiAPI(); .changeDocument()
 *: api.changeDocument(변경할 문서의 타이틀, 편집 요약, 변경할 문서의 내용) => 문서의 내용을 변경합니다.
 *: api.addDocument(변경할 문서의 타이틀, 편집 요약, 추가할 문서의 내용) => 문서에 새로운 내용을 추가합니다.
 *: api.getDocument(가져올 문서의 타이틀) => 문서의 모든 텍스트를 읽어옵니다.
 *: api.readDocument(가져올 문서의 타이틀) => 문서의 모든 텍스트를 jquery 객체로 읽어옵니다.
 * 영 좋지 않은 목적으로 사용 하면 안드로메다 경찰관이 잡아간다!
 */

function MediaWikiAPI() {
	console.warn('권장하지 않는 MediaWikiAPI를 사용하고 있습니다. 대신 mw.Api를 사용해 주세요.');
	
    var token;
    var getToken = function() {
        if (token !== undefined) return token;
        $.ajax({
            url: "/api.php?action=query&meta=tokens", // Note: URL은 서버 디렉토리 설정에 따라 바꾸어야 합니다.
            success: function(v, i) {
                var datas = JSON.parse($(v).find("pre").text());
                token = datas.query.tokens.csrftoken;
            },
            async: false
        });
        return token;
    };

    function changeDocument(title, summary, content, isUnReload, minor) {
    	mw.loader.using( ['mediawiki.util','mediawiki.Title'] ).then( function () {
		    $.ajax({
	            url: mw.util.wikiScript("api"),
	            data: {
	                format: 'json',
	                action: 'edit',
	                title: title,
	                summary: summary,
	                text: content,
	                minor: minor,
	                token: getToken(),
	            },
	            dataType: 'json',
	            type: 'POST',
	            success: function(data) {
	                if (data && data.edit && data.edit.result == 'Success') {
	                    if (!isUnReload) window.location.reload(); // reload page if edit was successful
	                } else if (data && data.error) {
	                    alert('Error: API returned error code "' + data.error.code + '": ' + data.error.info);
	                } else {
	                    alert('Error: Unknown result from API.');
	                }
	            },
	            error: function(xhr) {
	                alert('Error: Request failed.');
	            }
	        });
		} );
    }

    function addDocument(title, summary, content, isUnReload, minor) {
        originContent = getDocument(title);
        changeDocument(title, summary, originContent + content, isUnReload, minor);
    }

    function getDocument(title) {
        function entityDecode(doc) {
            return $('<p></p>').html(doc).text();
        }

        var originContent;
        $.ajax({
            url: "/" + wgScriptPath + "?title=" + title + "&action=edit",
            success: function ajaxSucess(data) {
                originContent = $(data).find("textarea").html();
            },
            async: false
        });
        return entityDecode(originContent);
    }

    function readDocument(title) {
        var doc;
        $.ajax({
            url: "/" + wgScriptPath + "/" + title,
            success: function ajaxSucess(data) {
                doc = $(data).find("#mw-content-text");
            },
            async: false
        });
        return doc;
    }


    return {
        getToken: getToken,
        changeDocument: changeDocument,
        addDocument: addDocument,
        getDocument: getDocument,
        readDocument: readDocument,
    };
}

/** @function fetchScript
 * 체크섬을 활용해 보다 안전하게 외부 스크립트를 가져올 수 있음
 * @author hsl0
**/
var fetchScript = fetch? function fetchScript(url, integrity) {
    return fetch(url, {
        header: {
            Accept: [
                'application/javascript',
                'application/ecmascript',
                'text/javascript',
                'application/x-javascript',
                '*/*'
            ]
        },
        integrity: integrity
    }).then(function(res) {
        return res.text().then(function(text) {
        	new Function(text)();
        	return new $.Deferred().resolve(text, res.statusText, res).promise();
        });
    });
} : $.getScript;
/**
 * API 에러가 반환될 경우 알려주는 함수
 * 저작자: [[사용자:hsl0|hsl0]]
 **/
function notifyApiError(msg, option, code, object) {
	option = option || {};
	mw.notification.notify(
        code === 'http'?
            $('<span />')
                .append($('<p />', {class: 'api-errmsg'}).text(object.xhr.responseText).html(option.additionalMessage || ''))
                .append($('<code />', {class: 'api-errcode'}).text('HTTP ' + object.xhr.status)) : 
            $('<span />')
                .append($('<p />', {class: 'api-errmsg'}).text(object.error.info).html(option.additionalMessage || ''))
                .append($('<code />', {class: 'api-errcode'}).text(code)),
        {
            title: msg,
            type: 'error',
            tag: option.tag,
            autoHideSeconds: 'long'
        }
    );
}
/** 링크경고
 * 자바스크립트로 링크에 경고를 넣을 수 있습니다.
 * 제작자: [[사용자:hsl0|hsl0]]
**/
function linkWarn(element, msg, msgClass) {
	return $(element)
		.addClass('linkwarn tooltip')
		.append($('<span class="tooltip-msg" />').append(msg).addClass(msgClass || 'messagebox'));
}

/**
 * [[리버티게임:오락실/2023년_8월#사이드바 '임의의 게임으로' 기능 관련]]
 * --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 8월 14일 (월) 10:36 (KST)
 */
$(function(){
    var triggered = false;
    var $linkwrapper = $("#n-randompage, .move-randompage").find("a");
	//[[틀:임의_게임]] 구현, 사이드바 임의게임으로 링크 바인딩
	$linkwrapper.on("click",function(e){
		var category = $(this).closest(".move-randompage").data("category") || undefined
		e.preventDefault();
        if(triggered) return;
        triggered = true;

		(new mw.Api()).get({
		    action: 'parse',
		    page: '리버티게임:임의 게임',
		    formatversion: 2,
		    category:category
		}).then(function(res){
		    var page = $(res.parse.text).find(".redirect-random-page").text().trim();
		    location.href = mw.util.getUrl(page);
		}).catch(function(){
		    location.href = mw.util.getUrl("리버티게임:임의 게임",{category:category});
		});
	}).attr("rel","nofollow");

	//[[리버티게임:임의_게임]] 구현
	if($("#content .redirect-random-page").length){
    	history.replaceState(null, null, mw.util.getUrl($("#content .redirect-random-page").text().trim()));
    	location.reload();
	}
});

/**
 * 리버티게임 인기 게임 순위 정렬
 * ver 1.2.1 --{{사용자:Senouis/서명}} 2024년 9월 15일 (일) 16:43 (KST)
*/
$(function (){
	var sectionRatings = document.getElementsByClassName("section-ratings");
	var sectionRatings_param = "4";
	if (sectionRatings.length === 0) return;
	if (document.getElementById("sectionRatings-parameter")) sectionRatings_param = document.getElementById("sectionRatings-parameter").innerText;
	for (var i in sectionRatings){
		var param1 = sectionRatings.item(i).innerText;
		fetch("https://libertyga.me/rest.php/sectionratings/v0/ratings/"+param1+"/" + sectionRatings_param).then(function (result){return result.json();}).then(function (result){
			if (result.result !== "SUCCESS") return;
			if (!result.category) return;
			var sectionRatings = document.getElementsByClassName("section-ratings");
			if (Object.keys(result.gameList).length === 0){
				for (var k in sectionRatings){
					if (sectionRatings.item(k).innerText === result.category){
						sectionRatings.item(k).innerText = "\n\n\n\n\n\n";
						break;
					}
				}
				return;
			}
			var tempElement = document.createElement("div");
			tempElement.innerHTML = result.parseResult;
			for (var j in sectionRatings){
				if (sectionRatings.item(j).innerText === result.category){
					sectionRatings.item(j).innerText = "";
					var elemlist = tempElement.querySelectorAll(".gamecard");
					for (var idx in elemlist){
						try{
							var elem = elemlist.item(idx);
							sectionRatings.item(j).appendChild(elem);
						} catch (e) {
							continue;
						}
					}
					break; // 작업 종료
				}
			}
		}).catch(function(e){console.log(e);});
	}
});

/**
 * DisucussionTools가 알림 상자 틀을 망가뜨리는 문제 해결을 위한 스크립트(작동 중지)
 * --[[사용자:Senouis|Senouis]] ([[사용자토론:Senouis|토론]]) 2024년 8월 30일 (금) 11:47 (KST)
*/

$(function (){
	var amboces = document.getElementsByClassName("template-ambox");
	if (amboces.length === 0) return;
	for (var i in amboces) {
	    var problemistic = amboces.item(i).querySelector("div div span:first-child");
	    if (problemistic.id.substring(0,2) === "c-") {
	    	problemistic.style.display = "none";
	    }
	}
});

/**
 * 일반 이름공간 내에 있는 특정 분류의 문서 갯수를 가져오는 API 요청
 * v1.3--{{사용자:Senouis/서명}} 2024년 9월 19일 (목) 01:25 (KST)
*/
$(function () {
	var categorylist = document.getElementsByClassName("pagecount");
	if (categorylist.length === 0) return;
	var parameter = [];
	for (var i in categorylist) {
		var param = categorylist.item(i).innerText; // 이름공간을 제외하고 공백을 언더바(_)로 바꾼 분류 이름(예: 철도_교통_게임)을 파라미터로 함
		parameter.push(param); // namespace 0번(일반 이름공간) 내 분류 갯수를 세도록 파라미터를 삽입한다.
	}
	fetch("https://libertyga.me/rest.php/sectionratings/v0/categorycounter/"+parameter.join("|")+"/0").then(function (result){return result.json();}).then(function (result) {
		var categorylist2 = document.getElementsByClassName("pagecount");
		for (var i in result.count) {
			for (var j in categorylist2){
				if (categorylist2.item(j).innerText === result.category[i]){ // 파라미터와 result.category가 같으면 치환
					categorylist2.item(j).innerText = result.count[i] === null ? 0 : result.count[i];
					categorylist2.item(j).style.display = "initial";
					break;
				}
			}
		}
	});
});