사용자:기나ㅏㄴ/CatMan.js

위키백과, 우리 모두의 백과사전.

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다. 구글 크롬, 파이어폭스, 마이크로소프트 엣지, 사파리: ⇧ Shift 키를 누른 채 "새로 고침" 버튼을 클릭하십시오. 더 자세한 정보를 보려면 위키백과:캐시 무시하기 항목을 참고하십시오.

/***********************************************************************************
 * CatMan:  The category manager for MediaWiki wikis that is simple, lightweight,  *
 * and modern.  Nya nya.                                                           *
 *                                                                                 *
 * This script is largely a work in progress and may sometimes not work properly.  *
 * Please see the English Wikipedia for known problems that are currently being    *
 * fixed.                                                                          *
 ***********************************************************************************
 * IMPORTANT (particularly for those who are viewing a copy of the script):        *
 * THIS FILE IS AVAILABLE ON GITHUB AT https://github.com/Awesome-Aasim/CatMan     *
 * ALL PULL REQUESTS AND CHANGES MUST BE MADE THERE, OTHERWISE THEY WILL BE LOST   *
 * IF THE FILE AT THE REPOSITORY IS CHANGED OR REBUILT.                            *
 ***********************************************************************************
 * LICENSING INFORMATION: Licensed under the MIT license                           *
 * MIT License                                                                     *
 * Copyright (c) 2021 Aasim Syed                                                   *
 * Permission is hereby granted, free of charge, to any person obtaining a copy    *
 * of this software and associated documentation files (the "Software"), to deal   *
 * in the Software without restriction, including without limitation the rights    *
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell       *
 * copies of the Software, and to permit persons to whom the Software is           *
 * furnished to do so, subject to the following conditions:                        *
 * The above copyright notice and this permission notice shall be included in all  *
 * copies or substantial portions of the Software.                                 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR      *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,        *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE     *
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER          *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,   *
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE   *
 * SOFTWARE.                                                                       *
 ***********************************************************************************/
//한국어판 사용 설명은 [[사용자:기나ㅏㄴ/CatMan]]에 있습니다.
//<nowiki>
if (!Catman && mw.config.get("wgNamespaceNumber") >= 0 && mw.config.get("wgIsProbablyEditable") && mw.config.get("wgArticleId") > 0 && mw.config.get("wgNamespaceNumber") != 10) {
    var Catman = {};
    mw.loader.using(["oojs-ui-core", "oojs-ui-windows", "oojs-ui-widgets", "oojs-ui.styles.icons-moderation", "oojs-ui.styles.icons-interactions", "oojs-ui.styles.icons-editing-core"], function () {
        Catman.start = function () {
            // Create a factory.
            Catman.factory = new OO.Factory();

            var categories = [];

            Catman.getEditableCategories = function (text) {
                var regexString = /\[\[\s*(분류|Category)\s*:\s*([^\|\]]+)(\|.+)?\]\]/;
                var regexI = new RegExp(regexString, "i");
                var regexIG = new RegExp(regexString, "ig");
                var result = text.match(regexIG);

                if (result != null) {
                    for(var i = 0; i < result.length; i++) {
                    categories.push(regexI.exec(result[i])[2].replace(/\s*$/, ""));
                    }
                }

                return categories;
            }

            function CatManDialog(config) {
                CatManDialog.super.call(this, config);
            }
            OO.inheritClass(CatManDialog, OO.ui.ProcessDialog);
            CatManDialog.static.name = 'catmandialog';
            CatManDialog.static.title = '카테고리 매니저';
            CatManDialog.static.actions = [
                {
                    flags: ['primary', 'progressive'],
                    icon: 'check',
                    title: '완료',
                    action: 'next',
                    disabled: false
                },
                {
                    flags: 'safe',
                    icon: 'close',
                    title: '취소',
                    action: 'back',
                    disabled: false
                }
            ]
            CatManDialog.prototype.getActionProcess = function (action) {
                var categoriestoadd, categoriestoremove, summary, presummary, wikitext;
                switch (action) {
                    case 'next':
                        return new OO.ui.Process(function () {
                            try {
                                categoriestoadd = [];
                                $(".catman-addcategory").each(function () {
                                    categoriestoadd.push($(this).find(".catman-categoryname").text());
                                });
                                categoriestoremove = [];
                                $(".catman-remove").each(function () {
                                    categoriestoremove.push($(this).find(".catman-categoryname").text());
                                });
                                summary = Catman.esinput.getValue();
                                presummary = (summary ? " " + summary + " / " : "") ;
                                if (categoriestoadd.length == 0 && categoriestoremove.length == 0) {
                                    throw new OO.ui.Error("추가하거나 제거할 분류가 없습니다.", { warning: true, recoverable: true });
                                }
                                return $.get(mw.config.get("wgScriptPath") + "/api.php", {
                                    action: "parse",
                                    format: "json",
                                    page: mw.config.get("wgPageName"),
                                    prop: "wikitext"
                                }).then(function (result, status) {
                                    if (status != 'success') {
                                        throw new OO.ui.Error("연결하지 못했습니다. 인터넷 연결을 확인하고 다시 시도하십시오.", {recoverable: true});
                                    }
                                    presummary += "[[사용자:기나ㅏㄴ/CatMan|CatMan]]을 이용하여 "
                                    wikitext = result.parse.wikitext["*"];

                                    for (var i in categoriestoremove) {
                                        for (var j in Catman.catprefixes) {
                                            if (wikitext.search("\\[\\[" + Catman.catprefixes[j][0].toUpperCase() + Catman.catprefixes[j].slice(start = 1) + ":" + categoriestoremove[i] + "\\]\\]") >= 0 || wikitext.search("\\[\\[" + Catman.catprefixes[j][0].toLowerCase() + Catman.catprefixes[j].slice(start = 1) + ":" + categoriestoremove[i] + "\\]\\]") >= 0) {
                                                presummary += "-[[분류:" + categoriestoremove[i].split("|")[0] + "]]"
                                            }
                                            if (i != categoriestoremove.length - 1) {
                                                presummary += ", "
                                            }
                                            while (wikitext.search("\\[\\[" + Catman.catprefixes[j][0].toUpperCase() + Catman.catprefixes[j].slice(start = 1) + ":" + categoriestoremove[i] + "\\]\\]") >= 0) {
                                                wikitext = wikitext.replace("[[분류:" + categoriestoremove[i] + "]]\n", "");
                                                wikitext = wikitext.replace("[[분류:" + categoriestoremove[i] + "]]", "");
                                            }
                                            while (wikitext.search("\\[\\[" + Catman.catprefixes[j][0].toLowerCase() + Catman.catprefixes[j].slice(start = 1) + ":" + categoriestoremove[i] + "\\]\\]") >= 0) {
                                                wikitext = wikitext.replace("[[분류:" + categoriestoremove[i] + "]]\n", "");
                                                wikitext = wikitext.replace("[[분류:" + categoriestoremove[i] + "]]", "");
                                            }
                                        }
                                    }
                                    if (categoriestoadd.length > 0 && categoriestoremove.length > 0) {
                                        presummary += "; "
                                    }
                                    
                                    var temptemp = 0;
                                    
                                    for (var i in categoriestoadd) {
                                        for (var j in Catman.catprefixes) {
                                            if (wikitext.search("\\[\\[" + Catman.catprefixes[j][0].toUpperCase() + Catman.catprefixes[j].slice(start = 1) + ":" + categoriestoadd[i] + "\\]\\]") < 0 && wikitext.search("\\[\\[" + Catman.catprefixes[j][0].toLowerCase() + Catman.catprefixes[j].slice(start = 1) + ":" + categoriestoadd[i] + "\\]\\]") < 0) {
                                              temptemp++;  
                                            }
                                        }
                                        
                                        if (temptemp == Catman.catprefixes.length) {
                                        presummary += "+[[분류:" + categoriestoadd[i].split("|")[0] + "]]"
                                        if (i != categoriestoadd.length - 1) {
                                                presummary += ", "
                                        }
                                        wikitext += "\n[[분류:" + categoriestoadd[i] + "]]";
                                        }
                                        temptemp = 0; // ADDED TEMPTEMP
                                    }
                                    
                                    return $.get(mw.config.get("wgScriptPath") + "/api.php", {
                                        action: "query",
                                        format: "json",
                                        meta: "tokens",
                                        type: "csrf"
                                    }).then(function (result, status) {
                                        if (status != 'success') {
                                            throw new OO.ui.Error("연결하지 못했습니다. 인터넷 연결을 확인하고 다시 시도하십시오.", {recoverable: true});
                                        }
                                        if (result.error) {
                                            throw new OO.ui.Error(result.error.info, { recoverable: true });
                                        } else {
                                            return $.post(mw.config.get("wgScriptPath") + "/api.php", {
                                                action: "edit",
                                                format: "json",
                                                title: mw.config.get("wgPageName"),
                                                token: result.query.tokens.csrftoken,
                                                text: wikitext,
                                                summary: presummary
                                            }).then(function (result, status) {
                                                if (status != 'success') {
                                                    throw new OO.ui.Error("연결하지 못했습니다. 인터넷 연결을 확인하고 다시 시도하십시오.", {recoverable: true});
                                                }
                                                if (result.error) {
                                                    throw new OO.ui.Error(result.error.info, { recoverable: true });
                                                } else {
                                                    Catman.windowManager.closeWindow('catmandialog');
                                                    Catman.windowManager.$element.remove();
                                                    mw.notify("분류를 편집했습니다. 다시 로드하는 중...");
                                                    location.reload();
                                                }
                                            });
                                        }
                                    });
                                });
                            } catch (error) {
                                return error;
                            }
                        }, this);
                    case 'back': return new OO.ui.Process(function () {
                        Catman.windowManager.closeWindow('catmandialog');
                        Catman.windowManager.$element.remove();
                    }, this);
                }
                // Fallback to parent handler
                return CatManDialog.super.prototype.getActionProcess.call(this, action);
            };
            function CategoriesLayout(name, config) {
                CategoriesLayout.super.call(this, name, config);
                this.$element.append('<span id="catman-categories"></span>');
            }
            OO.inheritClass(CategoriesLayout, OO.ui.TabPanelLayout);
            CategoriesLayout.prototype.setupTabItem = function () {
                this.tabItem.setLabel('분류 편집');
            }
            function SummaryLayout(name, config) {
                SummaryLayout.super.call(this, name, config);
                this.$element.append('<span id="catman-summary"></span>');
            }
            OO.inheritClass(SummaryLayout, OO.ui.TabPanelLayout);
            SummaryLayout.prototype.setupTabItem = function () {
                this.tabItem.setLabel('편집 요약');
            }
            CategoriesLayout.prototype.getBodyHeight = function () {
                return "full";
            }
            SummaryLayout.prototype.getBodyHeight = function () {
                return "full";
            }
            CatManDialog.prototype.getBodyHeight = function () {
                return "full";
            }
            CatManDialog.prototype.initialize = function () {
                CatManDialog.super.prototype.initialize.call(this);
                this.content = new OO.ui.PanelLayout({ padded: false, expanded: false, $overlay: this.$overlay });
                var catinput = new OO.ui.ComboBoxInputWidget({ expanded: false, padded: true, placeholder: "분류 입력", options: [], $overlay: this.$overlay });
                var catinputsubmit = new OO.ui.ButtonWidget({ flags: ["primary", "progressive"], icon: "add", title: '분류 추가', $overlay: this.$overlay })
                var esinput = new OO.ui.TextInputWidget({ placeholder: "편집 요약", $overlay: this.$overlay });
                var catpage = new CategoriesLayout('categories', { expanded: false, $overlay: this.$overlay });
                var sumpage = new SummaryLayout('summary', { expanded: false, $overlay: this.$overlay });
                var index = new OO.ui.IndexLayout({ expanded: true, $overlay: this.$overlay });
                index.addTabPanels([catpage, sumpage]);
                this.content.$element.append('<span id="catman-loading"><p></p></span><span id="catman"></span>');
                this.$body.append(this.content.$element);
                var progressBar = new OO.ui.ProgressBarWidget( {
                    progress: false,
                    padded: true, 
                    $overlay: this.$overlay
                });
                $("#catman-loading").find("p").html(progressBar.$element);
                $("#catman").hide();
                $("#catman").html(index.$element);
                var catinputset = new OO.ui.FieldsetLayout({$overlay: this.$overlay});
                catinputset.addItems([
                    new OO.ui.ActionFieldLayout(catinput, catinputsubmit, {$overlay: this.$overlay})
                ]);
                $("#catman-categories").append(catinputset.$element);
                $("#catman-summary").append(esinput.$element);
                var categorylist = mw.config.get("wgCategories");
                Catman.catinput = catinput;
                Catman.catinputsubmit = catinputsubmit;
                Catman.esinput = esinput;
                Catman.catpage = catpage;
                Catman.sumpage = sumpage;
                Catman.index = index;
                Catman.catinputset = catinputset;
                Catman.$overlay = this.$overlay;
                $.get(mw.config.get("wgScriptPath") + "/api.php", {
                    action: "parse",
                    format: "json",
                    page: mw.config.get("wgPageName"),
                    prop: "wikitext"
                }).then(function (result, status) {
                    if (status != "success") {
                        Catman.windowManager.closeWindow('catmandialog');
                        Catman.windowManager.$element.remove();
                        OO.ui.alert('Failed to load CatMan.');
                    }
                    //find all category links on the page
                    var text = result.parse.wikitext["*"];
                    var catprefixes = [];
                    var editablelist = [];
                    var uneditablelist = [];
                    var editablecategory = false;

                    //LOAD NAMESPACE IDS
                    for (var i in mw.config.get("wgNamespaceIds")) {
                        if (mw.config.get("wgNamespaceIds")[i] == 14) {
                            catprefixes.push(i);
                        }
                    }

                    Catman.catprefixes = catprefixes;
                    editablelist = Catman.getEditableCategories(text);
                    Catman.list = editablelist;
                    
                    for (var i in categorylist) {
                        editablecategory = false;
                        for (var j in editablelist) {
                            if (categorylist[i] == editablelist[j]) {
                                editablecategory = true;
                                break;
                            }
                        }
                        if (!editablecategory) {
                            uneditablelist.push(categorylist[i]);
                        }
                    }
                    //END
                    
                    $("#catman-categories").append("<style>\n.catman-remove {\ntext-decoration:line-through;\n}</style>")
                    $("#catman-categories").append("<table style=\"width:100%\"><caption><b>편집 가능한 분류</b></caption><tbody id=\"catman-table\"></tbody></table>");
                    for (var i of editablelist) {
                        var $el = $("<tr class=\"catman-category catman-currentcategory\"><td class=\"catman-categoryname\"><a href=\"" + mw.config.get("wgArticlePath").replace("$1", "Category:" + i.split("|")[0]) + "\">" + i.split("|")[0] + "</a>" + (i.split("|").length > 1 ? "<span title=\"This is a category sort key, used to sort category entries when viewing the page in the category.\" style=\"text-decoration-line:underline;text-decoration-style:dotted;\">|" + i.split("|")[1] + "</span>" : "") + "</td><td class=\"catman-categoryremove\"></td></tr>")
                        $("#catman-table").append($el);
                        var removeCat = new OO.ui.ButtonWidget({
                            icon: 'trash',
                            title: '분류 삭제',
                            flags: 'destructive',
                            $overlay: Catman.$overlay,
                            classes: ['catman-categoryremovebutton']
                        });
                        $el.find(".catman-categoryremove").append(removeCat.$element);
                        removeCat.$element.click(function (e) {
                            e.preventDefault();
                            $(this).parent().parent().addClass("catman-remove");
                            $(this).parent().parent().find(".catman-undobutton").show();
                            $(this).hide();
                        });
                        var undoCat = new OO.ui.ButtonWidget({
                            icon: 'undo',
                            title: '삭제 취소',
                            $overlay: Catman.$overlay,
                            classes: ['catman-undobutton']
                        });
                        $el.find(".catman-categoryremove").append(undoCat.$element);
                        undoCat.$element.click(function (e) {
                            e.preventDefault();
                            $(this).parent().parent().removeClass("catman-remove");
                            $(this).parent().parent().find(".catman-categoryremovebutton").show();
                            $(this).hide();
                        });
                        undoCat.$element.hide();
                    }
                    if (uneditablelist.length > 0) {
                        $("#catman-categories").append("<table style=\"width:100%\"><caption><b>편집 불가능한 분류</b> (<span title=\"이 분류들은 틀에 포함되어 있거나 숨은 분류이기에 CatMan으로 편집할 수 없습니다. 이 분류들을 제거하려면 숨은 분류를 제거하거나 분류를 포함한 틀을 제거하십시오.\" style=\"text-decoration-line:underline;text-decoration-style:dotted;\">?</span>)</caption><tbody id=\"catman-uneditable\"></tbody></table>");
                        for (var i of uneditablelist) {
                            var $el = $("<tr><td class=\"catman-categoryname\"><a href=\"" + mw.config.get("wgArticlePath").replace("$1", "Category:" + i.split("|")[0]) + "\">" + i + "</a></td></tr>")
                            $("#catman-uneditable").append($el);
                        }
                    }
                    Catman.addCat = function (e) {
                        e.preventDefault();
                        if (catinput.getValue().length > 0) {
                            var $el = $("<tr class=\"catman-category catman-addcategory\"><td class=\"catman-categoryname\"><a href=\"" + mw.config.get("wgArticlePath").replace("$1", "Category:" + catinput.getValue().split("|")[0]) + "\">" + catinput.getValue().split("|")[0] + "</a>" + (catinput.getValue().split("|").length > 1 ? "<span title=\"분류 정렬 키로, 분류 이름공간에서 분류를 정렬하는 데 사용됩니다.\" style=\"text-decoration-line:underline;text-decoration-style:dotted;\">|" + catinput.getValue().split("|")[1] + "</span>" : "") + "</td><td class=\"catman-categoryremove\"></td></tr>")
                            $("#catman-table").append($el);
                            var removeCat = new OO.ui.ButtonWidget({
                                icon: 'trash',
                                title: '분류 삭제',
                                flags: 'destructive',
                                $overlay: Catman.$overlay
                            });
                            $el.find(".catman-categoryremove").append(removeCat.$element);
                            removeCat.$element.click(function (e) {
                                e.preventDefault();
                                $(this).parent().parent().remove();
                            });
                            catinput.setValue("");
                        }
                        $(".catman-categoryname").each(function() {
                            var that = this;
                            $.get(mw.config.get("wgScriptPath") + "/api.php", {
                                action: "parse",
                                format: "json",
                                page: "Category:" + $(this).text().split("|")[0]
                            }).done(function(result) {
                                if (result.error) {
                                    if (result.error.code == "missingtitle") {
                                        $(that).find("a").addClass("new");
                                    }
                                }
                            });
                        });
                    }
                    catinput.$element.keypress(function(e) {
                        if (e.which == 13) {
                            Catman.addCat(e);
                        } else {
                            var key = e.which || e.keyCode;
                            if (key == 91 || key == 93 || (catinput.getValue() == "" && key == 32) || (catinput.getValue().search("\\|") >= 0 && key == 124) || (catinput.getValue() == "" && key == 124) || key == 35 || key == 123 || key == 125 || key == 60 || key == 62) { // stop the input of forbidden wikitext characters (except for pipe which is used for category sorting)
                                e.preventDefault();
                            }
                        }
                    });
                    window.setInterval(function(e) {
                        //populate the combobox
                        var searchterm = catinput.getValue();
                        var splitsearch = searchterm.split("|");
                        $.get(mw.config.get("wgScriptPath") + "/api.php", {
                            "action": "query",
                            "format": "json",
                            "list": "search",
                            "utf8": 1,
                            "srsearch": splitsearch[0],
                            "srnamespace": "14"
                        }).then(function(result, status) {
                            if (status == "success") {
                                if (result.error) {
                                    catinput.setOptions([]);
                                } else {
                                    var options = [], searchresults = result.query.search;
                                    var restofsearchterm = "";
                                    for (var i in splitsearch) {
                                        if (i != 0) {
                                            restofsearchterm += splitsearch[i];
                                        }
                                        if (i != splitsearch.length - 1) {
                                            restofsearchterm += "|";
                                        }
                                    }
                                    for (var i in searchresults) {
                                        options.push({data: searchresults[i].title.split(":")[1] + restofsearchterm, label: searchresults[i].title.split(":")[1]});
                                    }
                                    if (options.length == 0) {
                                        options.push({data: searchterm, label: "검색 결과 없음"})
                                    }
                                    catinput.setOptions(options);
                                }
                            }
                        })
                    }, 1000);
                    catinputsubmit.$element.click(Catman.addCat);
                    $(".catman-categoryname").each(function() {
                        var that = this;
                        $.get(mw.config.get("wgScriptPath") + "/api.php", {
                            action: "parse",
                            format: "json",
                            page: "Category:" + $(this).text()
                        }).done(function(result) {
                            if (result.error) {
                                if (result.error.code == "missingtitle") {
                                    $(that).find("a").addClass("new");
                                }
                            }
                        });
                    });
                    $("#catman").show();
                    $("#catman-loading").hide();
                });
            };
            // Register the window constructor with the factory.
            Catman.factory.register(CatManDialog);

            // Create a window manager. Specify the name of the factory with the ‘factory’ config.
            Catman.windowManager = new OO.ui.WindowManager({
                factory: Catman.factory
            });
            $(document.body).append(Catman.windowManager.$element);
            Catman.windowManager.openWindow('catmandialog', { size: "full" });
        };
        if (mw.config.get("skin") == "minerva") {
            mw.util.addPortletLink('p-tb', 'javascript:Catman.start()', '분류 편집', 'pt-catman');
        } else {
            mw.util.addPortletLink('p-cactions', 'javascript:Catman.start()', '분류 편집', 'pt-catman');
        }
    });
}
//</nowiki>