Открыть меню
Открыть персональное меню
Вы не представились системе
Your IP address will be publicly visible if you make any edits.

Модуль:Tabs

Материал из wiki.iccup.org

Модуль Module:Tabs используется для создания вкладок на страницах iCCup, предоставляя как статические, так и динамические табы для организации и структурирования информации.

API

Программное имя: Tabs


static (args: table?) → Html?

Создает статические вкладки.




dynamic (args: table) → Html

Создает динамические вкладки.




_readArguments (args: table, options: table) → table

Обрабатывает аргументы, переданные в шаблон, и определяет, какие из них использовать для создания вкладок.




_setThis (tabArgs: table) → nil

Устанавливает текущую вкладку на основе текущего URL или других условий.




_buildContentDiv (hasContent: boolean, hybridTabs: boolean, noPadding: boolean) → Html

Создает контейнер для содержания вкладок.




_single (tab: table, showHeader: boolean) → Html

Создает одиночную вкладку, если передан только один аргумент.




_getDisplayNameFromLink (link: string) → string

Получает имя для отображения из ссылки.





Посмотрите всю нашу документацию iCCup здесь.



Пример использования

Пример 1: Статические вкладки

{{#invoke:Tabs|static|name1=Вкладка 1|link1=Page1|name2=Вкладка 2|link2=Page2}}

Этот пример создаст две статические вкладки: "Вкладка 1" и "Вкладка 2", каждая из которых будет ссылаться на Page1 и Page2 соответственно.

Пример 2: Динамические вкладки

<pre> {{#invoke:Tabs|dynamic|name1=Вкладка 1|content1=Содержание 1|name2=Вкладка 2|content2=Содержание 2}} </pre>

Этот пример создаст две динамические вкладки, переключаясь между "Содержание 1" и "Содержание 2" при нажатии на "Вкладка 1" и "Вкладка 2".

Параметры

  • name<sub>n</sub>: Название вкладки, где n — номер вкладки.
  • link<sub>n</sub>: Ссылка для вкладки, если вкладка должна быть статической.
  • content<sub>n</sub>: Содержимое вкладки, если вкладка динамическая.
  • tabs<sub>n</sub>: Дополнительные вкладки, которые могут быть вложены в текущую.
  • This: Указывает, какая вкладка должна быть активной.
  • This2: Дополнительный параметр для указания активной вкладки.



---
-- @iCCup
-- wiki=commons
-- page=Module:Tabs
--
-- This module is adapted for iCCup.
--

local Array = require('Module:Array')
local Class = require('Module:Class')
local Logic = require('Module:Logic')
local Operator = require('Module:Operator')
local Page = require('Module:Page')
local Table = require('Module:Table')

local Tabs = {}

---Creates static tabs.
---Entry point of Template:Tabs static
---@param args table?
---@return Html|string?
function Tabs.static(args)
    args = args or {}

    local tabArgs = Tabs._readArguments(args, {allowThis2 = true})
    local tabCount = #tabArgs
    if tabCount == 0 then return '' end -- Возвращаем пустую строку, если табов нет

    Tabs._setThis(tabArgs)

    local tabs = mw.html.create('ul')
        :attr('class', 'nav nav-tabs navigation-not-searchable tabs tabs' .. tabCount)
        :attr('data-nosnippet')

    local subTabs = mw.html.create()

    Array.forEach(tabArgs, function(tab)
        local name = tab.name or (tab.link and Tabs._getDisplayNameFromLink(tab.link)) or ''
        local text = tab.link and Page.makeInternalLink({}, name, tab.link) or tab.name or ''
        tabs:tag('li'):addClass(tab.this and 'active' or nil):wikitext(text)
        subTabs:node(tab.this and tab.tabs or nil)
    end)

    return mw.html.create()
        :tag('div')
            :addClass('tabs-static')
            :attr('data-nosnippet', '')
            :node(tabs)
            :done()
        :node(subTabs)
end

---Creates dynamic tabs.
---Entry point of Template:Tabs dynamic
---@param args table
---@return Html|string?
function Tabs.dynamic(args)
    args = args or {}

    local tabArgs = Tabs._readArguments(args, {removeEmptyTabs = Logic.readBool(args.removeEmptyTabs)})
    local tabCount = #tabArgs
    if tabCount == 0 then return '' end -- Возвращаем пустую строку, если табов нет

    local hasContent = Array.all(tabArgs, function(tab) return Logic.isNotEmpty(tab.content) end)
    local allEmpty = Array.all(tabArgs, function(tab) return Logic.isEmpty(tab.content) end)
    assert(hasContent or allEmpty, 'Some of the tabs have contents while others do not')

    local isSingular = tabCount == 1 and hasContent
    if isSingular and not Logic.readBool(args.showSingularAsTab) then
        return Tabs._single(tabArgs[1], not Logic.readBool(args.suppressHeader))
    end

    local tabs = mw.html.create('ul')
        :addClass('nav nav-tabs tabs tabs' .. tabCount)

    if not Array.any(tabArgs, Operator.property('this')) then
        tabArgs[1].this = true
    end

    local build = function(obj, elementType, content, class, isActive)
        if not obj or not elementType then return end -- Проверка аргументов
        local element = mw.html.create(elementType)
            :addClass(class)
            :addClass(isActive and 'active' or nil)
            :newline()
            :node(content)

        obj:newline():node(element)
    end

    Array.forEach(tabArgs, function(tabData, tabIndex)
        build(tabs, 'li', tabData.name, 'tab' .. tabIndex, tabData.this)
    end)

    if not Logic.nilOr(Logic.readBoolOrNil(args['hide-showall']), isSingular) then
        tabs:tag('li')
            :addClass('show-all')
            :wikitext('Show All')
    end

    tabs:newline()

    local contents = Tabs._buildContentDiv(
        hasContent,
        Logic.readBool(args['hybrid-tabs']),
        Logic.readBool(args['no-padding'])
    )

    if not hasContent then
        return '<div class="tabs-dynamic navigation-not-searchable" data-nosnippet>\n'
            .. tostring(tabs) .. contents
    end

    Array.forEach(tabArgs, function(tabData, tabIndex)
        build(contents, 'div', tabData.content, 'content' .. tabIndex, tabData.this)
    end)

    return mw.html.create('div')
        :addClass('tabs-dynamic navigation-not-searchable')
        :attr('data-nosnippet')
        :node(tabs)
        :newline()
        :node(contents)
end

---@param args table
---@param options {allowThis2: boolean?, removeEmptyTabs: boolean?}
---@return {name: string?, link: string?, content: string|Html?, tabs: string|Html?, this: boolean}[]
function Tabs._readArguments(args, options)
    local tabArgs = {}
    local tabIndex = 1
    local thisTab = tonumber(args.This)
    local this2Tab = tonumber(args.This2)

    while args['name' .. tabIndex] or args['link' .. tabIndex] do
        if args['content' .. tabIndex] or not options.removeEmptyTabs then
            table.insert(tabArgs, {
                name = Table.extract(args, 'name' .. tabIndex),
                link = Table.extract(args, 'link' .. tabIndex),
                content = Table.extract(args, 'content' .. tabIndex),
                tabs = Table.extract(args, 'tabs' .. tabIndex),
                this = thisTab == tabIndex or (options.allowThis2 and this2Tab == tabIndex),
            })
        end
        tabIndex = tabIndex + 1
    end

    if Logic.readBool(args.returnIfEmpty) then
        return tabArgs
    end

    assert(Logic.isNotEmpty(tabArgs), 'You are trying to add a "Tabs" template without arguments for names nor links')

    return tabArgs
end

---@param tabArgs {name: string?, link: string?, content: string|Html?, tabs: string|Html?, this: boolean}[]
function Tabs._setThis(tabArgs)
    if Array.any(tabArgs, Operator.property('this')) then return end

    local fullPageName = mw.title.getCurrentTitle().prefixedText
    local this

    local maxLinkLength = -1

    Array.forEach(tabArgs, function (tab, tabIndex)
        local link = tab.link
        if not link then return end
        link = link:gsub('_', ' ')
        local linkLength = string.len(link)
        local charAfter = string.sub(fullPageName, linkLength + 1, linkLength + 1)
        local pagePartial = string.sub(fullPageName, 1, linkLength)
        if pagePartial == link and (charAfter == '/' or charAfter == '') and linkLength > maxLinkLength then
            maxLinkLength = linkLength
            this = tabIndex
        end
    end)

    if not this then return end

    tabArgs[this].this = true
end

---@param hasContent boolean
---@param hybridTabs boolean
---@param noPadding boolean
---@return Html|string
function Tabs._buildContentDiv(hasContent, hybridTabs, noPadding)
    if hasContent then
        local contentDiv = mw.html.create('div')
            :addClass('tabs-content')
        if hybridTabs then
            contentDiv
                :css('border-style', 'none !important')
                :css('padding', '0 !important')
        elseif noPadding then
            contentDiv
                :css('padding', '0 !important')
        end
        return contentDiv
    end

    local style = ''
    if hybridTabs then
        style = 'border-style:none !important; padding:0 !important;'
    elseif noPadding then
        style = 'padding:0 !important;'
    end
    return '\n<div class="tabs-content" style="' .. style .. '">'
end

---@param tab {name: string?, link: string?, content: string|Html?, tabs: string|Html?, this: boolean}
---@param showHeader boolean
---@return Html
function Tabs._single(tab, showHeader)
    local header
    if showHeader then
        header = mw.html.create()
            :tag('h6'):wikitext(tab.name):done()
            :newline()
    end
    return mw.html.create()
        :node(header)
        :node(tab.content)
end

---@param link string
---@return string
function Tabs._getDisplayNameFromLink(link)
    local linkParts = mw.text.split(link, '/', true)
    return linkParts[#linkParts]
end

return Class.export(Tabs)