Участник:I am smiling/LinksHighlighter.js

// Окрашивает внутренние ссылки в редакторе вики-кода при включённой подсветке синтаксиса:
// рабочие ссылки - в синий цвет
// нерабочие - в красный
// перенаправления - в зелёный
// [ДАННЫЕ УДАЛЕНЫ] - в серый
//
// Для корректной работы скрипта необходимо задать кастомные стили,
// см. .cm-link-* в [[:meta:User:I am smiling/global.css]]

mw.loader.using(['ext.wikiEditor']).then(() => {
    mw.loader.using(['mediawiki.api', 'jquery']).then(() => {
        function highlightLinks(cm) {
            const doc = cm.getDoc();
            const text = doc.getValue();
            const linkRegex = /\[\[([^\[\]|]+)(?:\|[^\[\]]+)?\]\]/g;

            const titles = new Set();
            let match;
            while ((match = linkRegex.exec(text)) !== null) {
                titles.add(match[1].trim());
            }

            getLinkStatuses([...titles]).then(statuses => {
                cm.addOverlay({
                    token: function (stream) {
                        if (stream.match(/\[\[[^\[\]|]+(?:\|[^\[\]]+)?\]\]/)) {
                            const raw = stream.current();
                            const m = raw.match(/^\[\[([^\[\]|]+)(?:\|.*)?\]\]$/);
                            if (!m) return null;
                            const title = m[1].trim();
                            const status = statuses[title] || 'grey';
                            return `link-${status}`;
                        } else {
                            stream.next();
                            return null;
                        }
                    }
                });
            });
        }

        async function getLinkStatuses(titles) {
            const result = {};
            const chunks = [];

            for (let i = 0; i < titles.length; i += 50) {
                chunks.push(titles.slice(i, i + 50));
            }

            for (const chunk of chunks) {
                try {
                    const data = await new mw.Api().get({
                        action: 'query',
                        format: 'json',
                        redirects: 1,
                        titles: chunk.join('|')
                    });

                    for (const [id, page] of Object.entries(data.query.pages)) {
                        const title = page.title;
                        if (parseInt(id) < 0) result[title] = 'red';
                        else if (page.redirect) result[title] = 'green';
                        else result[title] = 'blue';
                    }

                    if (data.query.redirects) {
                        for (const redir of data.query.redirects) {
                            result[redir.from] = result[redir.to] === 'blue' ? 'green' : result[redir.to];
                        }
                    }
                } catch (e) {
                    console.warn('Status not found', e);
                }
            }

            return result;
        }

        // Запускаем изначально (если CodeMirror включён сразу)
        const initialCM = $(".wikiEditor-ui .CodeMirror")[0]?.CodeMirror;
        if (initialCM) {
            highlightLinks(initialCM);
        }

        // Слушаем появления новых CodeMirror после переключения чекбокса
        new MutationObserver(() => {
            const cm = $(".wikiEditor-ui .CodeMirror")[0]?.CodeMirror;
            if (cm && !cm._wikilinkOverlayAdded) {
                cm._wikilinkOverlayAdded = true; // чтобы не дублировать
                highlightLinks(cm);
            }
        }).observe(document.body, { childList: true, subtree: true });
    });
});
Prefix: a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9

Portal di Ensiklopedia Dunia

Kembali kehalaman sebelumnya