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

Модуль:Tabs: различия между версиями

Материал из wiki.iccup.org
Новая страница: «--- -- @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? function Tabs.st...»
 
Нет описания правки
Строка 19: Строка 19:
---Entry point of Template:Tabs static
---Entry point of Template:Tabs static
---@param args table?
---@param args table?
---@return Html?
---@return Html|string?
function Tabs.static(args)
function Tabs.static(args)
args = args or {}
    args = args or {}


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


Tabs._setThis(tabArgs)
    Tabs._setThis(tabArgs)


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


local subTabs = mw.html.create()
    local subTabs = mw.html.create()


Array.forEach(tabArgs, function(tab)
    Array.forEach(tabArgs, function(tab)
-- if tab.name is unset tab.link is set as per `Tabs._readArguments`
        local name = tab.name or (tab.link and Tabs._getDisplayNameFromLink(tab.link)) or ''
local name = tab.name or Tabs._getDisplayNameFromLink(tab.link --[[@as string]])
        local text = tab.link and Page.makeInternalLink({}, name, tab.link) or tab.name or ''
local text = tab.link and Page.makeInternalLink({}, name, tab.link) or tab.name
        tabs:tag('li'):addClass(tab.this and 'active' or nil):wikitext(text)
tabs:tag('li'):addClass(tab.this and 'active' or nil):wikitext(text)
        subTabs:node(tab.this and tab.tabs or nil)
subTabs:node(tab.this and tab.tabs or nil)
    end)
end)


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


Строка 57: Строка 56:
---@return Html|string?
---@return Html|string?
function Tabs.dynamic(args)
function Tabs.dynamic(args)
args = args or {}
    args = args or {}


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


local hasContent = Array.all(tabArgs, function(tab)
    local hasContent = Array.all(tabArgs, function(tab) return Logic.isNotEmpty(tab.content) end)
return Logic.isNotEmpty(tab.content) end)
    local allEmpty = Array.all(tabArgs, function(tab) return Logic.isEmpty(tab.content) end)
local allEmpty = Array.all(tabArgs, function(tab)
    assert(hasContent or allEmpty, 'Some of the tabs have contents while others do not')
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
    local isSingular = tabCount == 1 and hasContent
if isSingular and not Logic.readBool(args.showSingularAsTab) then
    if isSingular and not Logic.readBool(args.showSingularAsTab) then
return Tabs._single(tabArgs[1], not Logic.readBool(args.suppressHeader))
        return Tabs._single(tabArgs[1], not Logic.readBool(args.suppressHeader))
end
    end


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


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


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


obj:newline():node(element)
        obj:newline():node(element)
end
    end


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


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


tabs:newline()
    tabs:newline()


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


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


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


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


Строка 136: Строка 128:
---@return {name: string?, link: string?, content: string|Html?, tabs: string|Html?, this: boolean}[]
---@return {name: string?, link: string?, content: string|Html?, tabs: string|Html?, this: boolean}[]
function Tabs._readArguments(args, options)
function Tabs._readArguments(args, options)
local tabArgs = {}
    local tabArgs = {}
local tabIndex = 1
    local tabIndex = 1
local this = tonumber(args.This)
    local thisTab = tonumber(args.This)
local this2 = tonumber(args.This2)
    local this2Tab = tonumber(args.This2)


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


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


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


return tabArgs
    return tabArgs
end
end


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


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


-- Finds the link that is a prefix of the current page. If there are more than one, choose the longest, then first.
    local maxLinkLength = -1
-- For example, if the current page is ab/cd/e3, then among
--  ab/cd/e1
--  ab/cd/e2
--  ab/cd/e
--  ab/cd
--  ab/cg
--  ab
-- it will pick ab/cd.
local maxLinkLength = -1


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


if not this then return end
    if not this then return end


tabArgs[this].this = true
    tabArgs[this].this = true
end
end


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


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


Строка 231: Строка 214:
---@return Html
---@return Html
function Tabs._single(tab, showHeader)
function Tabs._single(tab, showHeader)
local header
    local header
if showHeader then
    if showHeader then
header = mw.html.create()
        header = mw.html.create()
:tag('h6'):wikitext(tab.name):done()
            :tag('h6'):wikitext(tab.name):done()
:newline()
            :newline()
end
    end
return mw.html.create()
    return mw.html.create()
:node(header)
        :node(header)
:node(tab.content)
        :node(tab.content)
end
end


Строка 245: Строка 228:
---@return string
---@return string
function Tabs._getDisplayNameFromLink(link)
function Tabs._getDisplayNameFromLink(link)
local linkParts = mw.text.split(link, '/', true)
    local linkParts = mw.text.split(link, '/', true)
return linkParts[#linkParts]
    return linkParts[#linkParts]
end
end


return Class.export(Tabs)
return Class.export(Tabs)

Версия от 18:49, 24 сентября 2024

Модуль 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)