미디어위키:Gadget-defaultTemplate.js

리버티게임, 모두가 만들어가는 자유로운 게임

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.

  • 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
  • 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
  • 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
  • 오페라: Ctrl-F5를 입력.
/**
 * [[틀:뒤로]], [[틀:새로고침]], [[틀:앞으로]]에서 사용하는 방문기록 이동 함수
 * class="historygo" data-page="(이동 위치)"
 * 작성자: [[사용자:hsl0|hsl0]]
**/

$(function historygo() {
	$('.historygo').wrap('<a />').click(function() {
	    history.go(this.dataset.page);
	});
});


/** [[틀:로고 바꾸기]]용 함수 V 1.1
 * 작성자: [[사용자:Manymaster|manymaster]],
 * 1.1, 1.2 업데이트: [[사용자:BANIP|BANIP]]
 * 1.3 업데이트: [[사용자:Senouis|Senouis]]
 */
function logochange() {
    var logo = $(".template-changelogo img").attr("src");
    if (logo === undefined) {return;} // 로고 바꾸기 틀이 없는 경우 조기 종료
    var logoUrl = new URL(logo, location.href);
    // 로고 실행 경로가 위키미디어 공용이거나 현재 위키일때만 로고변경
    if( ['upload.wikimedia.org', location.host].includes(logoUrl.host)){
		// 벡터 레거시
    	$(".skin-vector-legacy #p-logo .mw-wiki-logo").css({
			"background-image": "url(" + logo + ")",
			"background-size": "contain"
		});
		// 벡터 2022
        $(".skin-vector-2022 .mw-logo-icon").attr("src", logo);
        // 모노북은 현재 그림 위치를 찾지 못하여 로고 변경 미지원
        // 타임리스
        $(".timeless-logo img").attr("src", logo);
    }
}
$(logochange);
/* [[틀:로고 바꾸기]]용 함수 끝 */

/** [[틀:제목 바꾸기]]용 스크립트 */
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);

/** [[틀:복붙 상자]]용 함수
 * [[틀:자동저장|자동저장 시스템]]이 자동 인증 사용자 전용인 관계로 자동저장 시스템을 사용하지 못하거나 안 하는 사용자를 위해 쉽게 내용을 복붙할 수 있도록 도와주는 함수입니다.
 * 작성자: [[사용자:Manymaster|manymaster]]
 */
function cvbox() {

    var i;
    var cvdata = [];
    var box = [];
    var cvbox = [];
    
    /* 틀 사용 여부 확인 */
	for(i = 0;
    document.getElementsByClassName("cvdata")[i] !== undefined && 
	document.getElementsByClassName("box_locator")[i] !== undefined; i++)
	{
    
	/* 복붙 상자에 넣을 내용을 불러오고 문제가 되는 문자열 치환 */
	cvdata.push(document.getElementsByClassName("cvdata")[i].innerHTML);
	cvdata[i] = cvdata[i].replace(/(<([^>]+)>)/ig, "");
	cvdata[i] = cvdata[i].replace(/\n+/gi, "\n");
	
	/* 지정한 위치에 복붙 상자를 만들어 내용 넣기 */
	box.push(document.getElementsByClassName("box_locator")[i]);
	box[i].innerHTML = '<textarea class="ctrlcvbox" onclick="this.focus();this.select()" title="클릭 후 Ctrl+C 등으로 \'복사\'하시면 클립보드에 내용이 저장됩니다." readonly>' + cvdata[i] + '</textarea>';
	
	/* 복붙 상자 크기 조정 */
	cvbox.push(document.getElementsByClassName("ctrlcvbox")[i]);
	cvbox[i].style.height = (2+cvbox[i].scrollHeight)+"px";
	}
	return;    
}
$( cvbox );

/* [[틀:복붙 상자]]용 함수 끝 */

/** [[틀:편집불가]]에서 사용
  * - 1차 리뉴얼: [[사용자:Manymaster|manymaster]]
 * - 2차 리뉴얼: [[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 7월 21일 (금) 13:24 (KST)
 */
function editprevent() {
    var $def = $(".edit-prevent");
    if(!$def.length) return;
    $("#ca-ve-edit, #p-cactions, #ca-history").hide();
    $("#ca-edit a")
        .html($def.data("title") || "잠김")
        .html($def.data("text") || "잠김")
        .click(function(e){e.preventDefault();});
}
$( editprevent );

/** [[틀:편집낚시에서 사용]]
 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 7월 21일 (금) 13:36 (KST)
 */
function editFake() {
    var $def = $(".edit-fake");
    if(!$def.length) return;
    var editTargetPagename = $def.data("target-edit");
    var historyTagetPagename = $def.data(".edit-fake") || editTargetPagename;

    var interceptPage = function(e,pagename){
        e.preventDefault();
        var urlParams = {};
        var searchParams = new URLSearchParams(window.location.search);
        searchParams.forEach(function(value, key){ urlParams[key] = value; });
        location.href = mw.util.getUrl(pagename, urlParams);
    };
    $("#ca-history a").click(function(e){ interceptPage(e,historyTagetPagename); });
    $("#ca-edit a, #ca-ve-edit a").click(function(e){ interceptPage(e,editTargetPagename); });
}
$( editFake );

/** [[틀:고급 넘겨주기]]에서 사용하는 넘겨주기 함수
 * id="advredirect" data-url="(문서명)" 
 * 작성자: [[사용자:Gustmd7410|Gustmd7410]] */

$('#advredirect').each(function() {
	location.replace(location.origin + $(this).data('url'));
});

/** JSON 편집을 편리하게 해 주는 기능.
 *  [[틀:JSON수정]]을 위한 플러그인입니다.
 *  작성자: [[사:Bd3076|Bd3076]]
 */

function uncy_jsonEdit(){
	if($('.uncy-jsonedit').length === 0) return;
	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 편집을 편리하게 해 주는 기능 끝 */

/* [[틀:탭 이름]]에서 사용 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 7월 21일 (금) 10:43 (KST) */
$(function(){
	var $tabName = $("#template-change-tab-name");
	if($tabName.length) $("#p-associated-pages .mw-list-item:nth-child(1) span").text($tabName.data('value'));
});
/* [[틀:탭 추가]]에서 사용 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 8월 26일 (토) 17:42 (KST) */
$(function(){
    $(".template-add-tab").toArray().forEach(function(el){
        var $this = $(el);
        var targetTab = $this.data("target");
        var targetPage = $this.text().trim();
        var label = $this.data("label") || targetPage;
        var title = $this.data("title") || (label + '로 이동');
        var url = targetPage;
        var urlAttribute = ' rel="discussion"';
        // 링크 하위요소가 있을 경우 해당 링크의 목적지를 지정 
        if($this.find("a").length > 0){
            url = $this.find("a").attr("href");
        }

        var isInnerLink = (url.indexOf("/") !== 0 || url.indexOf("?") === -1) && (url.slice(0, 4) !== "http");
        if( isInnerLink ){
            // 문서경로
            if(targetPage.indexOf("../") === 0 || targetPage.indexOf("/") === 0){
                // 상대 문서경로
                var fullpagename = mw.config.get("wgPageName").split("/");
                
                // ../로 시작하는 만큼 상위로 이동
                while(targetPage.indexOf("../") === 0){
                    targetPage = targetPage.slice(3);
                    fullpagename.pop();
                }
                // 첫 글자가 /로 시작하는 경우 삭제
                if(targetPage.indexOf("/") === 0){
                    targetPage = targetPage.slice(1);
                }

                // /로 시작하는 만큼 하위로 이동
                targetPage.split("/").forEach(function(el){
                    fullpagename.push(el);
                });

                targetPage = fullpagename.join("/");
            } else {
                // 절대 문서경로
            }
            url = mw.util.getUrl(targetPage);
        } else {
            // 외부링크
            urlAttribute = ' rel="nofollow" class="external';
        }

        var parentSelector;
        switch(targetTab){
            case '좌측':
                parentSelector = "#p-associated-pages";
            break;
            case '우측':
                parentSelector = "#p-views";
            break;
            default:
                parentSelector = "#p-cactions";
        }

        var $target = $(parentSelector).find(".vector-menu-content-list");

        $target.append('' + 
        '<li class="mw-list-item">' + 
            '<a href="' + url + '" ' + urlAttribute + ' title="' + title + '">' + 
                '<span>' + label + '</span>' + 
            '</a>' + 
        '</li>'
        );
    });
});

/* [[틀:예시]]에서 사용 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 9월 5일 (화) 16:32 (KST) */
$(function(){
    // 예시 페이지로 이동
    var moveExample = function(title, content) {
        var pagename = '리버티게임:연습장';
        fetch('/index.php?title=' + pagename + '&action=edit')
        .then(function(res){
            return res.text();
        })
        .then(function(doc){
            var $body = $(doc);
            //#editform을 현재 document에 추가하고 action=submit으로 바꾼 뒤 submit
            var $from = $body.find('#editform').css("display","none").appendTo(document.body);
            $from.append('<input type="hidden" name="wpPreview" value="미리 보기">');
            $from.append('<input type="hidden" name="mode" value="text">');
            //내용 변경
            $from.find('#wpTextbox1').text(function(el,text){
                return text.split("\n")[0] + "\n== " + title + " ==" + "\n" + content;
            });
            
            $from.attr('action', '/index.php?title=' + pagename + '&action=submit').submit();
        });
    };

    // 해당 예시정보 긁어오기
    var getExampleInfo = function($example) {
        var code = $example.find(".frm-code .frm-content").text().trim();
        var $cursor = $example;
        //$cursor 상위에 p 엘리멘트가 있는 경우 이동
        if( $cursor.closest("p").length ) {
            $cursor = $cursor.closest("p");
        }
        // 이전 요소로 쭈욱 이동
        while(1) {
            $cursor = $cursor.prev();
            // 이전 요소가 없거나 h1~h6 태그인 경우 종료
            if(($cursor[0] === undefined) || $cursor[0].tagName.match(/h[1-6]/i) ) break;
        }

        // 내용 확인 및 콘솔에 출력
        var title = mw.config.get('wgPageName');
        // $cursor 있으면 텍스트 가져와서 추가
        if($cursor.length) {
            title += " - " + $cursor.find(".mw-headline").text().trim();
        }

        return {
            code:code, title:title
        };
    };

    // 예시틀의 소스 확인 버튼에 이벤트 바인딩
    var $executes = $(".frm-code-example-wrapper .frm-code-execute");
    $executes.on("click",function(){
        // 모든 예시 실행 버튼 이벤트 바인딩 해제
        $executes.off("click");
        // 로딩아이콘으로 변경
        $(this).find(".material-symbols-outlined").css("animation","rotate 3s linear infinite").text("sync");
        // 메세지로 사용자에게 알리기
        mw.notify("연습장 페이지로 이동합니다...");

        var exampleInfo = getExampleInfo($(this).closest('.frm-code-example-wrapper'));
        moveExample(exampleInfo.title, exampleInfo.code);
    });

});


/* [[틀:뱃지그룹]]에서 사용 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 9월 6일 (수) 09:18 (KST) */
/* 변경된 [[틀:알림 상자]]에 대응 — {{사용자:hsl0/서명}} 2024년 10월 22일 (화) 05:24 (KST) */
$(function(){
    var $badgeGroups = $(".template-badges-param");
    if($badgeGroups.length === 0) return;
    $("#template-badges-output").remove();
    $("#catlinks").after("<div id='template-badges-output'></div>");
    var $output = $("#template-badges-output");

    var colorToHSL = (function() {
        var canvas = document.createElement('canvas');
        canvas.width = canvas.height = 1;
        var ctx = canvas.getContext('2d', { willReadFrequently: true });
    
        var memoize = function(factory, ctx) {
            var cache = {};
            return function(key) {
                if (!(key in cache)) cache[key] = factory.call(ctx, key);
                return cache[key];
            };
        };
    
        function rgbToHsl(r, g, b) {
            r /= 255, g /= 255, b /= 255;
            var max = Math.max(r, g, b), min = Math.min(r, g, b);
            var h, s, l = (max + min) / 2;
            if (max == min) h = s = 0;
            else {
                var d = max - min;
                s = l > 0.5 ? d / (2.0 - max - min) : d / (max + min);
                if (max == r) h = (g - b) / d + (g < b ? 6 : 0);
                else if (max == g) h = (b - r) / d + 2;
                else h = (r - g) / d + 4;
                h /= 6;
            }
            return [Math.round(h*360), Math.round(s*100), Math.round(l*100)];
        }
    
        return memoize(function(col) {
            ctx.fillStyle = col;
            ctx.fillRect(0, 0, 1, 1);
            var data = ctx.getImageData(0, 0, 1, 1).data;
            return rgbToHsl(data[0], data[1], data[2]);
        });
    })();
    
    //param = {image or imageLink, title, descriptTitle, descriptContent, borderColor, backgroundColor}
    var buildBadge = function(param){
        var imageText = "<img class='image' src='" + param.imageLink + "'>";
        if(param.image){
            imageText = "<div class='image-wrapper'>" + param.image + "</div>";
        }

        // 테마컬러 획득
        var invertedHslArray = colorToHSL(param.borderColor);
        // 명도가 30% 이상이면 10%, 이하면 90%로 색 반전
        invertedHslArray[2] = invertedHslArray[2] > 30 ? 10 : 90;
        var invertedThemeColor = "hsl(" + 
        	invertedHslArray.map(function(v,i){ return i > 0? v + "%" : v; }).join(",") + 
        ")";

        var $badge = $(
            "<div class='template-badge'>" +
                imageText +
                "<div class='tooltip'>" + $("<div>" + param.title + "</div>").text().trim() + "</div>" +
                "<div class='descript'>" +
                    "<div class='title'>" + param.title + "</div>" +
                    (param.content && ("<div class='content'>" + param.content + "</div>")) +
                "</div>" +
            "</div>"
        ).css({
            '--color-theme': param.borderColor,
            '--color-theme-inverted': invertedThemeColor,
            '--color-background': param.backgroundColor,
        });
        return $badge;
    };

    $badgeGroups.toArray().forEach(function(el){
        var $group = $(el);


        // [[틀:알림상자]]를 변경할 때마다 반드시 여기를 편집
        $group.children(".ambox").toArray().forEach(function(amboxElement){
            var $ambox = $(amboxElement);
            // $ambox의 border left 색
            var descriptHtml = $ambox.find(".ambox-detail").html();
            var $title = $ambox.find(".ambox-title");

            var $badge = buildBadge({
                imageLink: $ambox.find(".ambox-image img").attr("src"), 
                title:  $title.html(),
                content: descriptHtml,
                borderColor: $title.css("background-color"),
                backgroundColor: $ambox.css("background-color")
            });
            
            $output.append($badge);
        });

        // [[틀:유저박스]]
        $group.children(".template-userbox").toArray().forEach(function(el){
            var $userbox = $(el);
            var $icon = $(el).find(".userbox-icon");
            var $content = $(el).find(".userbox-content");

            var badgeParam = {
                title:  $content.html(),
                content: "",
                borderColor: $icon.css("background-color"),
                backgroundColor: $userbox.css("background-color")
            };
            // 유저박스의 아이콘 이미지가 있으면 imageLink로, 없으면 image로
            var $iconIamge = $icon.find("img");
            if( $iconIamge.length > 0 ){
                badgeParam.imageLink = $iconIamge.attr("src");
            } else {
                badgeParam.image = $icon.html();
            }

            var $badge = buildBadge(badgeParam);
            $output.append($badge);
        });
    });

    

    // badge를 클릭했을 때 descript를 표시
    $(document).on('click', '.template-badge', function(e) {
        $(".template-badge").removeClass("active");
        $(this).addClass("active");
        e.stopPropagation();
    });

    // badge 이외의 영역을 클릭했을 때 descript를 감춤
    $(document).on('click', function() {
        $(".template-badge").removeClass("active");
    });
});