Модуль:Delink

Матеріал з Вікіпедії — вільної енциклопедії.
Jump to navigation Jump to search


{{Модуль:Delink}} (і·о·д·р··#)

Модуль реалізує {{Delink}}.


-- Вилучає з вікітексту внутрішні і зовнішні посилання.

require('Модуль:No globals')

local p = {}

local getArgs

local function delinkReversePipeTrick(s)
    if s:match("^%[%[|.*[|\n]") then -- Перевірити наявність нових рядків або багаторазових пайпів.
        return s
    else
        return s:match("%[%[|(.*)%]%]")
    end
end

local function delinkPipeTrick(s)
    local linkarea, display = "", ""
    -- Необхідно опрацювати двокрапки, дужки і коми.
    
    -- Спочатку видаляємо текст перед першою двокрапкою, якщо вона є.
    if s:match(":") then
        s = s:match("%[%[.-:(.*)|%]%]")
    -- Якщо двокрапок немає, залишити весь текст, крім квадратних дужок і пайпа.
    else
        s = s:match("%[%[(.*)|%]%]")
    end
    
    -- Наступна стадія — дужки і коми.
    if s:match("%(.-%)$") then -- У дужок пріоритет над комами.
        s = s:match("(.-) ?%(.-%)$")
    elseif s:match(",") then -- Якщо дужок немає, вивести тільки текст перед першою комою.
        s = s:match("(.-),.*$")
    end
    return s
end

local function delinkWikilink(s)
    local result = s
    -- Опрацювати трюк зі зворотним пайпом.
    if result:match("%[%[|") then
        return delinkReversePipeTrick(result)
    end
    
    result = mw.uri.decode(result, "PATH") -- Декодувати сутності, кодовані знаком відсотку. Залишити підкреслювання і плюси.
    result = mw.text.decode(result, true) -- Декодувати сутності HTML.
    
    -- Перевірити некоректні заголовки. Для цього потрібно визначити
    -- область посилання, тобто частину перед пайпом.
    local titlearea
    if result:match("|") then -- Перевірити, чи маємо справу з пайп-посиланням.
        titlearea = result:match("^%[%[(.-)|.*%]%]")
    else
        titlearea = result:match("^%[%[(.-)%]%]")
    end
    -- Перевірити наявність некоректних символів.
    if mw.ustring.match(titlearea, "[%[%]<>{}%%%c\n]") then
        return s
    end
    
    -- Перевірити наявність категорій, інтервікі і файлів.
    local colonprefix = result:match("%[%[(.-):.*%]%]") or "" -- Отримати текст перед першою двокрапкою.
    local ns = mw.site.namespaces[colonprefix] -- Пересвідчитися, що зазначено відомий простір імен.
    if mw.language.isKnownLanguageTag(colonprefix)
    or ( ns and ( ns.canonicalName == "Файл" or ns.canonicalName == "Категорія" ) ) then
        return ""
    end
    
    -- Видалити двокрапку, якщо посилання містить трюк з двокрапкою.
    if result:match("%[%[:") then
        result = "[[" .. result:match("%[%[:(.*%]%])")
    end
    
    -- Опрацювати посилання, які містять трюк з пайпом.
    if mw.ustring.match(result, "^%[%[[^|]*|%]%]") then
        return delinkPipeTrick(result)
    end
    
    -- Знайти область відображення вікі-посилання
    if result:match("|") then -- Визначити, чи посилання містить пайп.
        result = result:match("^%[%[.-|(.+)%]%]")
        -- Не відображати нові рядки багаторядкових пайп-посилань,
        -- де яких пайп стоїть перед першим новим рядком.
        result = result:gsub("\n", "")
    else
        result = result:match("^%[%[(.-)%]%]")
    end

    return result
end

local function delinkURL(s)
    -- Припустимо, що внутрішні посилання вже прибрані,
    -- після чого залишився текст між двома квдратними дужками [foo].
    
    -- Якщо текст містить розрив рядка, він не відформатований як веб-адреса, незалежно від іншого вмісту.
    if s:match("\n") then
        return s
    end
    
    -- Перевірити наявність валідного URL-префіксу і принаймні одного валідного URL-символу.
    local valid_url_prefixes = {"//", "http://", "https://", "ftp://", "gopher://", "mailto:", "news:", "irc://"} 
    local url_prefix
    for i,v in ipairs(valid_url_prefixes) do
        if mw.ustring.match(s, '^%[' .. v ..'[^"%s].*%]' ) then
            url_prefix = v
            break
        end
    end
    
    -- Отримати текст для виводу
    if not url_prefix then
        return s
    end
    s = s:match("^%[" .. url_prefix .. "(.*)%]") -- Забрати весь текст після префіксу в веб-адресі і перед останньою квадратною дужкою.
    s = s:match('^.-(["<> ].*)') or "" -- Забрати весь текст після першого символу-роздільника в веб-адресі ("<> ).
    s = mw.ustring.match(s, "^%s*(%S.*)$") or "" -- Якщо символ-роздільник — пробіл, прибрати його.
    
    local s_decoded = mw.text.decode(s, true)
    if mw.ustring.match(s_decoded, "%c") then
        return s
    else    
        return s_decoded
    end
end

local function delinkLinkClass(s, pattern, delinkFunction)
    if not type(s) == "string" then
        error("Спроба прибрати посилання з нерядкового вводу.", 2)
    end
    if not ( type(pattern) == "string" and mw.ustring.sub(pattern, 1, 1) == "^" ) then
        error('Виявлено некоректний патерн. Патерни повинні починатися з "^".', 2)
    end
    -- Повторити для текстового рядка з заміною необхідного тексту, застосовуючи 
    -- функцію видалення посилань. Необхідно опрацьовувати текст символ за символом, а не
    -- через gsub, інакше вкладені посилання не виявляються належним чином.
    local result = ""
    while s ~= '' do
        -- Замінити текст, використовуючи одну ітерацію gsub.
        s = mw.ustring.gsub(s, pattern, delinkFunction, 1)
        -- Приєднати крайній символ зліва до похідного рядка.
        result = result .. mw.ustring.sub(s, 1, 1)
        s = mw.ustring.sub(s, 2, -1)
    end
    return result
end

function p._delink(args)
    local text = args[1] or ""
    if args.refs == "так" then
        -- Прибрати усі стріп-маркери, що репрезентують теги ref. Може привести до
        -- небажаних результатів — використовуйте тільки тоді, коли точно знаєте, що робите!
        text = mw.ustring.gsub(text, "UNIQ%w*%-ref%-%d*%-QINU", "")
    end
    if not (args.comments == "ні") then
        text = text:gsub("<!%-%-.-%-%->", "") -- Прибрати коментарі html.
    end
    if not (args.wikilinks == "ні") then
        text = delinkLinkClass(text, "^%[%[.-%]%]", delinkWikilink) -- Прибрати внутрішні посилання.
    end
    if not (args.urls == "ні") then
        text = delinkLinkClass(text, "^%[.-%]", delinkURL) -- Прибрати зовнішні посилання.
    end
    if not (args.whitespace == "ні") then
        -- Замінити одиночні нові рядки одним пробілом, але залишити подвійні нові рядки
        -- і нові рядки, які містять тільки пробіли або символи табуляції перед другим новим рядком.
        text = mw.ustring.gsub(text, "([^\n \t][ \t]*)\n([ \t]*[^\n \t])", "%1 %2")
        text = text:gsub("[ \t]+", " ") -- Прибрати додаткові символи табуляції і пробіли.
    end
    return text
end

function p.delink(frame)
    if not getArgs then
    	getArgs = require('Модуль:Arguments').getArgs
    end
    return p._delink(getArgs(frame, {wrappers = 'Шаблон:Delink'}))
end

return p