Greasy Fork is available in English.

Link Formatter

Форматирует ссылки

// ==UserScript==
// @name         Link Formatter
// @icon         https://www.google.com/s2/favicons?domain=shikimori.me
// @namespace    https://shikimori.one
// @version      1.1
// @description  Форматирует ссылки
// @author       LifeH
// @match        *://shikimori.org/*
// @match        *://shikimori.one/*
// @match        *://shikimori.me/*
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    "use strict";

    function URLcheck(str) {
        let pattern = new RegExp('^(http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\/~+#-]*[\\w@?^=%&\/~+#-])', 'i');
        return !!pattern.test(str.trim());
    }

    function formatter(clipboard, selectedText) {
        let formattedText = null;

        if (!URLcheck(clipboard)) {
            return;
        }

        const url = new URL(clipboard);
        const urlType = url.pathname.split('/');
        let id = urlType[2]?.split('-')[0];

        if (id && id.startsWith('z')) {
            id = id.substring(1);
        }

        selectedText = selectedText.trim();
        if (!selectedText) {
            return;
        }

        if (url.hostname.includes("shikimori") && urlType.length >= 3) {
            switch (urlType[1]) {
                case 'characters':
                    formattedText = `[character=${id}]${selectedText}[/character]`;
                    break;
                case 'ranobe':
                    formattedText = `[ranobe=${id}]${selectedText}[/ranobe]`;
                    break;
                case 'mangas':
                    formattedText = `[manga=${id}]${selectedText}[/manga]`;
                    break;
                case 'animes':
                    formattedText = `[anime=${id}]${selectedText}[/anime]`;
                    break;
                case 'persons':
                    formattedText = `[person=${id}]${selectedText}[/person]`;
                    break;
                default:
                    formattedText = `[url=${clipboard}]${selectedText}[/url]`;
                    break;
            }
        } else {
            formattedText = `[url=${clipboard}]${selectedText || clipboard}[/url]`;
        }

        return formattedText;
    }

    function vstavka(event, textarea) {
        let clipboardData = (event.originalEvent || event).clipboardData;
        if (!clipboardData) {
            return;
        }

        let clipboard = clipboardData.getData('text');

        if (!URLcheck(clipboard)) {
            return;
        }

        let selectedText = textarea[0].value.substring(textarea[0].selectionStart, textarea[0].selectionEnd);

        if (!selectedText.trim()) {
            return;
        }

        let formattedText = formatter(clipboard, selectedText);

        if (formattedText) {
            let text = textarea.val();
            let start = textarea[0].selectionStart;
            let end = textarea[0].selectionEnd;

            let newText = text.slice(0, start) + formattedText + text.slice(end);
            textarea.val(newText);

            textarea[0].setSelectionRange(start + formattedText.length, start + formattedText.length);

            event.preventDefault();
        }
    }

    function observeAreas() {
        let areas = [
            'textarea[name="review[body]"]',
            'textarea[name="comment[body]"]',
            'textarea[name="critique[text]"]',
            'textarea[name="club[description]"]',
            'textarea[name="club_page[text]"]',
            'textarea[name="message[body]"]',
            'textarea[name="article[body]"]',
            'textarea[name="anime[description_ru_text]"]',
            'textarea[name="anime[description_en_text]"]',
            'textarea[name="reason"]',
            'textarea[name="character[description_en_text]"]',
            'textarea[name="character[description_ru_text]"]',
            'textarea[name="manga[description_ru_text]"]',
            'textarea[name="manga[description_en_text]"]',
            'textarea[name="collection[text]"]',
            'textarea[name="anime[russia_released_on_hint]"]',
            'textarea[name="anime[more_info]"]',
        ];

        areas.forEach(function (selector) {
            let textarea = $(selector);
            if (textarea.length) {
                textarea.on('paste', function(event) {
                    vstavka(event, textarea);
                });
            }
        });
    }

    function ready(fn) {
        document.addEventListener('page:load', fn);
        document.addEventListener('turbolinks:load', fn);
        if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
            fn();
        } else {
            document.addEventListener('DOMContentLoaded', fn);
        }
    }

    ready(function () {
        observeAreas();
    });
})();