Karber:Mirzali/sort-çarnayış.js

Wikiqısebend ra

Note: Qeydi ra dıme, gani viriya cıgeyrayoği pak bo ke vurnayışi bıvêniyê.

  • Gışta şıma ke niya ro gocega Firefox / Safari: Shift ser, bıtıknê ra newe ra bar kerên ya zi Ctrl-F5 ya zi Ctrl-R bıtıknê (seba Mac ra ⌘-R).
  • Google Chrome: Ctrl-Shift-R ro nê. (seba Mac ra ⌘-Shift-R)
  • Internet Explorer / Edge: Ctrl ke niyo ro cı, Newe ke bıtıknê ya zi Ctrl-F5 bıkerê.
  • Opera: Ctrl-F5 bıtıknê.
// <nowiki>
let langUtilsInstance;
$(document).ready(function() {
    mw.loader.using(['jquery.ui'], function() {
        mw.util.addCSS('#t-sortwerger { font-weight: normal; }');
        $(mw.util.addPortletLink('p-tb', '#', 'Sort-çarnayış', 't-sortcarnayis', 'Sort language codes in Çarnayış')).click(init);
    });
    langUtilsInstance = new LanguageUtilsAsync();

    function init() {
        sortWerger();
    }

    function LanguageUtilsAsync() {
        const langNameToLangCodePromise = new mw.Api().get({
            "action": "expandtemplates",
            "format": "json",
            "text": "{{#invoke:languages/javascript-interface|AllCanonicalToCode}}",
            "prop": "wikitext"
        }).then(function(response) {
            return JSON.parse(response.expandtemplates.wikitext);
        });

        const langCodeToLangNamePromise = langNameToLangCodePromise.then(function(name2code) {
            const code2name = {};
            for (const name in name2code) {
                code2name[name2code[name]] = name;
            }
            return code2name;
        });

        this.GetWiktionaryCodeByCanonicalName = function(canonicalName) {
            return langNameToLangCodePromise.then(function(r) {
                return r[canonicalName];
            });
        };

        this.GetCanonicalNameByWiktionaryCode = function(langcode) {
            return langCodeToLangNamePromise.then(function(r) {
                return r[langcode];
            });
        };
    }
    // Zazaki alphabet
    const zazakiAlphabet = "ABCÇDEÊFGĞHIİJKLMNOPQRSŞTUÛVWXYZǃǀǁǂ";

    function customSort(langNameA, langNameB) {

        const minLength = Math.min(langNameA.length, langNameB.length);

        for (let i = 0; i < minLength; i++) {
            const indexA = zazakiAlphabet.indexOf(langNameA[i]);
            const indexB = zazakiAlphabet.indexOf(langNameB[i]);

            if (indexA < indexB) {
                return -1;
            } else if (indexA > indexB) {
                return 1;
            }
        }

        return langNameA.length - langNameB.length;
    }


    var stripArabicDiacritics = {
        strip: "\u064B\u064C\u064D\u064E\u064F\u0650\u0651\u0652"
    };
    var stripGraveAndAcute = {
        strip: "\u0300\u0301"
    };
    var fullToHalfWidthNumbers = {
        from: "0123456789",
        to: "0123456789"
    };

    const diacriticStrippers = {
        ang: {
            from: "ĀāǢǣĊċĒēĠġĪīŌōŪūȲȳ",
            to: "AaÆæCcEeGgIiOoUuYy",
            strip: "\u0304\u0307",
        }, //macron and above dot
        ar: stripArabicDiacritics,
        aao: stripArabicDiacritics,
        acm: stripArabicDiacritics,
        acx: stripArabicDiacritics,
        adf: stripArabicDiacritics,
        aeb: stripArabicDiacritics,
        afb: stripArabicDiacritics,
        ajp: stripArabicDiacritics,
        apc: stripArabicDiacritics,
        apd: stripArabicDiacritics,
        arq: stripArabicDiacritics,
        ary: stripArabicDiacritics,
        arz: stripArabicDiacritics,
        fa: stripArabicDiacritics,
        ps: stripArabicDiacritics,
        sd: stripArabicDiacritics,
        ur: stripArabicDiacritics,
        chl: {
            from: "ÁáÉéÍíÓóÚú",
            to: "AaEeIiOoUu",
            strip: "\u0304",
        }, //acute accent
        he: {
            strip: "\u05B0\u05B1\u05B2\u05B3\u05B4\u05B5\u05B6\u05B7\u05B8\u05B9\u05BA\u05BB\u05BC\u05BD\u05BF\u05C1\u05C2",
            from: "-'\"",
            to: "־׳״",
        },
        la: {
            from: "ĀāĒēĪīŌōŪūȲȳ",
            to: "AaEeIiOoUuYy",
            strip: "\u0304",
        }, //macron
        lt: {
            from: "áãàéẽèìýỹñóõòúù",
            to: "aaaeeeiyynooouu",
            strip: "\u0340\u0301\u0303",
        },
        nci: {
            from: "ĀāĒēĪīŌōŪūȲȳ",
            to: "AaEeIiOoUu",
            strip: "\u0304",
        }, //macron
        //strip ́ and ̀ on Cyrillic Slavic languages, Serbo-Croatian has a longer list
        ru: stripGraveAndAcute,
        uk: stripGraveAndAcute,
        be: stripGraveAndAcute,
        bg: stripGraveAndAcute,
        orv: stripGraveAndAcute,
        cu: stripGraveAndAcute,
        rue: stripGraveAndAcute,
        mk: stripGraveAndAcute,
        sh: {
            from: "ȀȁÀàȂȃÁáĀāȄȅÈèȆȇÉéĒēȈȉÌìȊȋÍíĪīȌȍÒòȎȏÓóŌōȐȑȒȓŔŕȔȕÙùȖȗÚúŪūѝӣ",
            to: "AaAaAaAaAaEeEeEeEeEeIiIiIiIiIiOoOoOoOoOoRrRrRrUuUuUuUuUuии",
            strip: "\u030F\u0300\u0311\u0301\u0304",
        },
        sl: {
            from: "áÁàÀâÂȃȂȁȀéÉèÈêÊȇȆȅȄíÍìÌîÎȋȊȉȈóÓòÒôÔȏȎȍȌŕŔȓȒȑȐúÚùÙûÛȗȖȕȔệỆộỘẹẸọỌəł",
            to: "aAaAaAaAaAeEeEeEeEeEiIiIiIiIiIoOoOoOoOoOrRrRrRuUuUuUuUuUeEoOeEoOel",
            strip: "\u0301\u0300\u0302\u0311\u030f\u0323",
        },
        kk: stripGraveAndAcute,
        ky: stripGraveAndAcute,
        tg: stripGraveAndAcute,
        sa: {
            strip: "ः",
        },
        /** visarga **/
        bo: {
            strip: "།",
        },
        /** shad **/
        tr: {
            from: "ÂâÛû",
            to: "AaUu",
            strip: "\u0302",
        },
        ja: fullToHalfWidthNumbers,
        cmn: fullToHalfWidthNumbers,
        yue: fullToHalfWidthNumbers,
        nan: fullToHalfWidthNumbers,
        ko: fullToHalfWidthNumbers,
        zu: {
            strip_init_hyphen: true,
        }

    };

    function removeDiacritics(langCode, str) {
        var stripper = diacriticStrippers[langCode];
        if (stripper) {
            var map = makeMap(stripper);
            var output = applyMap(map, str);

            return output;
        }
        return str;
    }

    function stringOrNull(val) {
        return typeof val == "string" ? val : null;
    }

    function makeMap(obj) {
        var from = stringOrNull(obj.from);
        var to = stringOrNull(obj.to);
        var strip = stringOrNull(obj.strip);
        var map = {};

        if (from && to) {
            for (var i = 0; i < from.length; i++) {
                map[from.charAt(i)] = to.charAt(i);
            }
        }
        if (strip) {
            for (var ii = 0; ii < strip.length; ii++) {
                map[strip.charAt(ii)] = "";
            }
        }
        return map;
    }

    function applyMap(map, str) {
        var input = str.split("");
        var output = "";

        for (var i = 0; i < input.length; i++) {
            var char = input[i];
            var repl = map[char];
            output += repl ? repl : char;
        }
        return output;
    }

    function page_exists(lang_code, page) {
        var domain;
        var wm_liens = {
            'cmn': 'zh',
            'fra-nor': 'nrm',
            'gsw': 'als',
            'ko-Hani': 'ko',
            'lzh': 'zh-classical',
            'nan': 'zh-min-nan',
            'kmr': 'ku',
            'nb': 'no',
            'nn': 'no',
            'rup': 'roa-rup',
            'yue': 'zh-yue',
        };
        var wiktios = [
            'en', 'mg', 'fr', 'zh', 'lt', 'ru', 'es', 'el', 'pl', 'sv', 'ko',
            'nl', 'de', 'tr', 'ku', 'ta', 'io', 'kn', 'fi', 'vi', 'hu', 'pt',
            'chr', 'no', 'ml', 'my', 'id', 'it', 'li', 'ro', 'et', 'ja', 'te',
            'jv', 'fa', 'cs', 'ca', 'ar', 'eu', 'gl', 'lo', 'uk', 'br', 'fj',
            'eo', 'bg', 'hr', 'th', 'oc', 'is', 'vo', 'ps', 'zh-min-nan',
            'simple', 'cy', 'uz', 'scn', 'sr', 'af', 'ast', 'az', 'da', 'sw',
            'fy', 'tl', 'he', 'nn', 'wa', 'ur', 'la', 'sq', 'hy', 'sm', 'sl',
            'ka', 'pnb', 'nah', 'hi', 'tt', 'bs', 'lb', 'lv', 'tk', 'sk', 'hsb',
            'nds', 'kk', 'ky', 'be', 'km', 'mk', 'ga', 'wo', 'ms', 'ang', 'co',
            'sa', 'gn', 'mr', 'csb', 'ckb', 'ug', 'st', 'ia', 'sd', 'sh', 'si', 'mn',
            'tg', 'or', 'kl', 'vec', 'jbo', 'an', 'ln', 'fo', 'zu', 'gu', 'kw',
            'gv', 'rw', 'qu', 'ss', 'ie', 'mt', 'om', 'bn', 'pa', 'roa-rup',
            'iu', 'so', 'am', 'su', 'za', 'gd', 'mi', 'tpi', 'ne', 'yi', 'ti',
            'sg', 'na', 'dv', 'tn', 'ts', 'ha', 'ks', 'ay',
        ];
        var keepApos = [
            'fr', 'de',
        ];


        if (wm_liens.hasOwnProperty(lang_code)) {
            domain = wm_liens[lang_code] + '.wiktionary';
        } else if (lang_code === 'navz') {
            domain = 'species.wikimedia';
        } else if ($.inArray(lang_code, wiktios) !== -1) {
            domain = lang_code + '.wiktionary';
        }

        // Si le Wiktionnaire n'existe pas, inutile de faire une requête HTTP
        if (!domain) {
            return $.Deferred().resolve('ç').promise();
        }

        // traiter l'apostrophe typographique comme une apostrophe dactylographique
        // dans les liens interwikis, les autres wiktionnaires privilégiant la seconde
        if ($.inArray(lang_code, keepApos) === -1) {
            page = page.replace('’', "'");
            page = page.replace('ʼ', "'");
        }


        const normalizedPageTitle = removeDiacritics(lang_code, page);
        var def = $.Deferred();
        $.ajax({
            url: '//' + domain + '.org/w/api.php?origin=' + location.protocol + '//' + location.host,
            data: {
                action: 'query',
                titles: normalizedPageTitle,
                format: 'json'
            },
            dataType: 'json'
        }).fail(function() {
            def.resolve('ç');
        }).then(function(data) {
            // The page title is already normalized, so no need to normalize again.
            // We can directly use the data to check for existence.
            // If the AJAX request succeeds, check if the page exists in the API response.
            // If it exists, resolve the promise with 'W+' (indicating existence).
            // Otherwise, resolve the promise with 'W-' (indicating non-existence).
            def.resolve(data.query.pages[-1] ? 'ç' : 'ç+');

        });

        return def.promise();
    }

    function fetchLanguageNames(langCodes) {
        return Promise.all(langCodes.map(langCode => {
            return langUtilsInstance.GetCanonicalNameByWiktionaryCode(langCode).then(languageName => {
                return {
                    langCode,
                    languageName,
                };
            });
        }));
    }

    function sortAlphabetically(content) {
        const wergerSections = extractWergerSections(content);

        if (wergerSections.length > 0) {
            const fetchPromises = wergerSections.map(wergerSection => {
                const lines = wergerSection.trim().split("\n");
                const langCodeRegex = /\{\{z\|([a-zA-Z-]+)(\|[^\}]+)?/;
                const langSet = [];

                let currentMainLang = null;

                for (let i = 0; i < lines.length; i++) {
                    const line = lines[i];
                    const langCodeMatches = line.match(langCodeRegex);
                    if (langCodeMatches !== null) {
                        const langCode = langCodeMatches[1]?.toLowerCase() || "";
                        if (!line.startsWith("*:")) {
                            if (currentMainLang) {
                                langSet.push(currentMainLang);
                            }
                            currentMainLang = {
                                type: 'mainLang',
                                line,
                                langCode,
                                subsets: [],
                            };
                        } else if (currentMainLang) {
                            currentMainLang.subsets.push(line);
                        }
                    } else {
                        if (currentMainLang) {
                            currentMainLang.subsets.push(line);
                        } else {
                            langSet.push({
                                type: 'unknown',
                                line,
                            });
                        }
                    }
                }

                if (currentMainLang) {
                    langSet.push(currentMainLang);
                }

                return fetchLanguageNames(langSet.filter(item => item.type === 'mainLang').map(item => item.langCode)).then(function(languageNames) {
                    langSet.sort((a, b) => {
                        if (a.type === 'mainLang' && b.type === 'mainLang') {
                            const langNameA = languageNames.find(lang => lang.langCode === a.langCode)?.languageName || "";
                            const langNameB = languageNames.find(lang => lang.langCode === b.langCode)?.languageName || "";
                            return customSort(langNameA, langNameB);
                        } else {
                            return a.type === 'mainLang' ? -1 : 1;
                        }
                    });
                    const sortedLines = langSet.reduce((result, item) => {
                        if (item.type === 'mainLang') {
                            result.push(item.line, ...item.subsets);
                        } else {
                            result.push(item.line);
                        }
                        return result;
                    }, []);

                    const sortedContent = "" + sortedLines.join("\n") + "";
                    content = content.replace(new RegExp(escapeRegExp(wergerSection), "g"), sortedContent);
                    return content;
                });
            });

            return Promise.all(fetchPromises).then(() => {
                return content;
            });
        }

        return Promise.resolve(content);
    }

    function extractWergerSections(content) {
        const wergerSections = [];
        const wergerSerRegex = /\{\{ç-ser(?:\|[^}]+)?}}/gi; // Regular expression to match {{werger-ser}} with optional arguments

        let match;
        while ((match = wergerSerRegex.exec(content)) !== null) {
            const startIndex = match.index;
            const endIndex = content.indexOf("{{ç-bın}}", startIndex);
            if (endIndex !== -1) {
                const sectionContent = content.substring(startIndex + match[0].length, endIndex).trim();
                wergerSections.push(sectionContent);
            } else {
                break;
            }
        }

        return wergerSections;
    }

    function updateWTemplateOutcome($textBox) {
        const langCodeRegex = /\{\{ç(\+|-)?\|([^\|]+)\|([^\|\}]+)/g;

        let match;
        let promises = [];

        while ((match = langCodeRegex.exec($textBox.val())) !== null) {
            const fullMatch = match[0];
            const sign = match[1] || '+';
            const langCode = match[2].toLowerCase();
            const page = match[3];

            const promise = page_exists(langCode, page).then(function(outcome) {
                const newTemplate = `{{ç${outcome === 'ç+' ? '+' : '-'}|${langCode}|${page}`;
                $textBox.val($textBox.val().replace(fullMatch, newTemplate));
            });

            promises.push(promise);
        }

        return Promise.all(promises);
    }

    window.sortWerger = function() {
        const $textBox = $("#wpTextbox1");

        if ($textBox.length > 0 && $textBox.val().includes("{{ç-ser") && $textBox.val().includes("{{ç-bın}}")) {
            sortAlphabetically($textBox.val()).then(function(sortedContent) {
                $textBox.val(sortedContent);
                mw.notify("Hatine rêzkirin");
                return updateWTemplateOutcome($textBox); // Pass the $textBox as an argument
            }).then(function() {
                mw.notify("Sererastkirinên W-/+ çêbû.");
                mw.notify("Xilas.");
            }).catch(function(error) {
                mw.notify("Failed to fetch language names or update W templates: " + error);
            });
        } else {
            mw.notify("Required templates not found on page: " + mw.config.get("wgTitle"));
        }
    }

    function escapeRegExp(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function flatten(arr) {
        return arr.reduce((flat, toFlatten) => flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten), []);
    }
});

// </nowiki>