Модуль:Навигация учебника
Внешний вид
Для документации этого модуля может быть создана страница Модуль:Навигация учебника/doc
local p = {}
local TRIM_PATTERN = "^%s*(.-)%s*$"
local LINE_PATTERN = "[^\n]+"
local FILTER_PATTERN = "^[%*#:]"
local LINK_PATTERN = "%[%[([^%]]-)%]%]"
local function trim(s)
return (s:gsub(TRIM_PATTERN, "%1"))
end
function p.nav(frame)
local args = frame.args
local parentTitle = args.main or args[1]
local currentSubPage = args.page or args[2]
if not parentTitle or not currentSubPage then
error("Ошибка: не переданы обязательные аргументы 'main' и 'page'.")
end
-- Оставляем только имя подстраницы после последнего слеша
local slashPos = currentSubPage:find("/", 1, true)
if slashPos then
currentSubPage = trim(currentSubPage:match(".*/(.*)"))
else
currentSubPage = trim(currentSubPage)
end
local parentPageObj = mw.title.new(parentTitle)
if not parentPageObj or not parentPageObj.exists then
error("Страница '" .. parentTitle .. "' не найдена.")
end
local parentContent = parentPageObj:getContent() or ""
if parentContent == "" then
error("Не удалось получить содержимое страницы '" .. parentTitle .. "'.")
end
-- Извлекаем весь блок {{Содержание}} вплоть до его закрытия
local contentBlock = parentContent:match("{{Содержание([%s%S]+)}}")
if not contentBlock then
error("Шаблон {{Содержание}} не найден на '" .. parentTitle .. "'.")
end
local pages = {}
for line in contentBlock:gmatch(LINE_PATTERN) do
local tline = trim(line)
if tline:match(FILTER_PATTERN) then
for link in tline:gmatch(LINK_PATTERN) do
local target, display = link:match("([^|]+)|(.+)")
local name = nil
if display then
name = trim(display)
else
local after = link:match(".*/(.*)")
name = trim(after or link)
end
table.insert(pages, name)
end
end
end
if #pages == 0 then
error("Не удалось извлечь список из {{Содержание}} на '" .. parentTitle .. "'.")
end
-- Поиск индекса текущей подстраницы
local currentIndex
for i, name in ipairs(pages) do
if name == currentSubPage then currentIndex = i; break end
end
if not currentIndex then
return ""
end
-- Формируем ссылки на соседние подстраницы
local prevLink, nextLink = "", ""
if currentIndex > 1 then
prevLink = string.format("[[%s/%s|%s]]", parentTitle, pages[currentIndex-1], pages[currentIndex-1])
end
if currentIndex < #pages then
nextLink = string.format("[[%s/%s|%s]]", parentTitle, pages[currentIndex+1], pages[currentIndex+1])
end
local navType = (args.type and args.type:lower()) or ""
if navType == "prev" then
return prevLink ~= "" and ("[[Файл:Left Arrow - The Noun Project.svg|25px|link=]] " .. prevLink) or ""
elseif navType == "next" then
return nextLink ~= "" and (nextLink .. " [[Файл:Right Arrow - The Noun Project.svg|25px|link=]]") or ""
else
local parts = {}
if prevLink ~= "" then table.insert(parts, prevLink) end
if nextLink ~= "" then table.insert(parts, nextLink) end
return table.concat(parts, " | ")
end
end
function p.getContent(frame)
local args = frame.args
local textbookName = args[1] or args.page or ""
if textbookName == "" then error("Ошибка: не указано название учебника.") end
local titleObj = mw.title.new(textbookName)
if not titleObj or not titleObj.exists then
error("Страница '" .. textbookName .. "' не найдена.")
end
local content = titleObj:getContent() or ""
if content == "" then
error("Страница '" .. textbookName .. "' пуста или недоступна.")
end
-- Извлечение всего блока {{Содержание}}
local contentBlock = content:match("{{Содержание([%s%S]+)}}")
if not contentBlock then
error("Шаблон {{Содержание}} не найден на '" .. textbookName .. "'.")
end
-- Парсинг названий подстраниц и стадий готовности
local pages, stages = {}, {}
for line in contentBlock:gmatch(LINE_PATTERN) do
local tline = trim(line)
if tline:match(FILTER_PATTERN) then
local link = tline:match(LINK_PATTERN)
local stageVal = tline:match("{{Стадия кор|([^}]-)}}") or "0%"
if link then
local target, display = link:match("([^|]+)|(.+)")
local name = display or (link:match(".*/(.*)") or link)
table.insert(pages, trim(name))
table.insert(stages, trim(stageVal))
end
end
end
-- Определяем текущую подстраницу через mw.title
local currentTitle = mw.title.getCurrentTitle()
local currentSubPage = currentTitle and currentTitle.prefixedText:match(textbookName .. "/(.+)")
if currentSubPage then currentSubPage = trim(currentSubPage) end
-- Ищем индекс и соответствующую стадию
local stage
if currentSubPage then
for i, name in ipairs(pages) do
if name == currentSubPage then
stage = stages[i]
break
end
end
end
-- Генерация итогового вывода
local full = "{{Содержание" .. contentBlock .. "}}"
local modified = full:gsub("(|%s*width%s*=%s*)100%%", "%130%%")
local output = mw.getCurrentFrame():preprocess(modified)
-- Исправление относительных ссылок
output = output:gsub("%[%[/(.-)|(.+)%]\]\]", string.format("[[%s/%%1|%%2]]", textbookName))
output = output:gsub("%[%[/(.-)%]\]\]", string.format("[[%s/%%1]]", textbookName))
if stage then
output = string.format("{{Готовность|%s}}\n%s", stage, output)
end
return output
end
return p