Дружба – это Чудо Вики
Advertisement
Дружба – это Чудо Вики

Для документации этого модуля может быть создана страница Модуль:Навбокс/Ядро/doc

local standartElements = {
    section = {
        children = true,
        level = 1,
        create = function( text, children )
            local section = mw.html.create( 'div' )
            section:addClass( 'navbox_section' )
            local header = mw.html.create( 'div' )
            header:addClass( 'navbox_sectionHeader' )
            header:wikitext( text )
            section:node( header )
            local body = mw.html.create( 'div' )
            body:addClass( 'navbox_sectionBody' )
            for i, child in ipairs( children ) do
                body:node( child )
            end
            section:node( body )
            return section 
        end
    },
    partition = {
        children = true,
        level = 2,
        create = function( text, children )
            local partition = mw.html.create( 'div' )
            partition:addClass( 'navbox_partition' )
            local header = mw.html.create( 'div' )
            header:addClass( 'navbox_partitionHeader' )
            header:wikitext( text )
            partition:node( header )
            local body = mw.html.create( 'div' )
            body:addClass( 'navbox_partitionBody' )
            for i, child in ipairs( children ) do
                body:node( child )
            end
            partition:node( body )
            return partition 
        end
    },
    content = {
        children = false,
        create = function( text )
            local body = mw.html.create( 'div' )
            body:addClass( 'navbox_content' )
            body:wikitext( text )
            return body
        end
    }
}
--
local navbox = {}
--[[settings(?) = table -- Настройки навбокса.
{
    attributes(?) = table -- Аттрибуты навбокса
    {
        classes(?) = string, -- Классы обертки навбокса;
        styles(?) = string, -- стили обертки навбокса;
        attrs(?) = string -- HTML атрибуты обертки навбокса.
    }
}
]]--
function navbox.create( settings )
    local self = navbox
    local obj = {}
    --
    if settings and settings.attributes then
        self._attributes = mw.clone( settings.attributes )
    end
    --
    obj._elementsRoot = {}
    obj._elements = {}
    obj._navbox = nil
    obj._modulesData = {}
    --
    obj._library = require( 'Модуль:Библиотека' )
    obj._elementsLibrary = mw.clone( standartElements )
    obj._modulesLibrary = require( 'Модуль:Навбокс/Модули' )
    --
    setmetatable( obj, self )
    self.__index = self
    return obj
end
--[[
params = table
{
    type = string -- Тип элемента;
    text = string -- текстовое содержимое элемента;
    id = string -- идентификатор элемента;
    parentId = string -- идентификатор элемента, который должен быть родительским добавляемому;
    attributes(?) = table -- Аттрибуты элемента;
    {
        classes(?) = string, -- Классы обертки навбокса;
        styles(?) = string, -- стили обертки навбокса;
        attrs(?) = string -- HTML атрибуты обертки навбокса.
    },
    modules(?) = table -- таблица модулей элемента.
}
]]--
function navbox:addElement( params )
    if self._navbox then
        error( 'Навбокс закрыт для расширения' )
    end
    self:_checkElement( params.type, params.id, params.parentId )
    if params.modules then
        self:_checkModules( params.modules, params.type, params.id )
    end
    local billet = self:_createBillet( params )
    self:_collectBillet( billet, params.parentId )
end
--[[
params = table
{
    type = string -- Тип элемента;
    text = string -- текстовое содержимое элемента;
    id = string -- идентификатор элемента;
    parentId = string -- идентификатор элемента, который должен быть родительским добавляемому;
    attributes(?) = table -- Аттрибуты элемента;
    {
        classes(?) = string, -- Классы обертки навбокса;
        styles(?) = string, -- стили обертки навбокса;
        attrs(?) = string -- HTML атрибуты обертки навбокса.
    },
    modules(?) = table -- таблица модулей элемента.
}
]]--
function navbox:_createBillet( params )
    local elementType = params.type
    local rawModules = params.modules
    local requiredModules = self._elementsLibrary[ elementType ].requiredModules
    local billet = {
        text = params.text,
        type = elementType,
        id = params.id
    }
    if params.attributes then
        billet.attributes = params.attributes
    end
    if rawModules or requiredModules then
        local modules = {}
        if rawModules then
            for name, setting in pairs( rawModules ) do
                local moduleSettings = mw.clone( setting )
                local dependences = self._modulesLibrary[ name ].dependences
                moduleSettings._name = name
                if dependences then
                    moduleSettings._dependences = {}
                    for i, dependence in ipairs( dependences ) do
                        if rawModules[ dependence ] then
                            dependencesData[ dependence ] = mw.clone( rawModules[dependence] )
                        end
                    end
                end
                table.insert( modules, moduleSettings )
            end
        end
        if requiredModules then
            for name, setting in pairs( requiredModules ) do
                if not rawModules[ name ] then
                    local moduleSettings = mw.clone( requiredModules[name] )
                    moduleSettings._name = name
                    table.insert( modules, moduleSettings )
                end
            end
        end
        table.sort( modules, function( mod1, mod2)
            local prior1 = self._modulesLibrary[ mod1._name ].priority
            local prior2 = self._modulesLibrary[ mod2._name ].priority
            return prior1 < prior2
        end )
        billet.modules = modules
    end
    return billet
end
--[[
elementType = string -- Тип элемента.
id = string -- Идентификатор элемента.
parentId = string -- Идентификатор элемента, который должен быть родительским добавляемому.
]]--
function navbox:_checkElement( elementType, id, parentId )
    local elementPattern = self._elementsLibrary[ elementType ]
    -- На верный тип элемента
    if not elementPattern then
        error( 'Несуществующий тип элементов' )
    end
    -- На корректный айди
    if self._elements[ id ] then
        error( 'Элемент "'..id..'", уже определён' )
    end
    -- На наличие в библиотеке требуемых модулей
    if elementPattern.requiredModules then
        for name, requiredModule in pairs( elementPattern.requiredModules ) do
            if not self._modulesLibrary[ name ] then
                error( 'Отсутствует требуемый для элемента "'..elementType..'" модуль "'..name..'"' )
            end
        end
    end
    if parentId then
        local parentElement = self._elements[ parentId ]
        -- Проверка на наличие родительского элемента
        if not parentElement then
            error( 'Блока "'..parentId..'", указанного как родительский блок для блока "'..id..'", не существует' )
        end
        local parentElementType = parentElement.type
        local parentElemetPattern = self._elementsLibrary[ parentElementType ]
        -- Проверка на возможность родительского элемента иметь дочерние элементы
        if not parentElemetPattern.children then
            error( 'Блок "'..parentId..'" типа "'..parentElementType..'" не может иметь дочерних блоков' )
        end
        -- Проверка на уровень элементов
        if elementPattern.children and elementPattern.level < parentElemetPattern.level then
            error( 'Блок "'..id..'" типа "'..elementType..'"  не может быть потомком блока "'..parentId..'" типа "'..parentElementType..'" по причине недостаточного уровня' )
        end
    end
end
--[[
    modules = table -- Таблица модулей элемента.
    elementType = string -- Тип элемента.
    id = string -- Идентификатор элемента.
]]--
function navbox:_checkModules( modules, elementType, id )
    local elementPattern = self._elementsLibrary[ elementType ]
    for name, settings in pairs( modules ) do
        local pattern = self._modulesLibrary[ name ]
        -- Проверка на существование модуля
        if not pattern then
            error( 'Элемент "'..id..'". Модуль "'..name..'" не существует' )
        end
        -- Проверка на разрешенный тип элемента
        local trueType
        for i, permittedElement in ipairs( pattern.typesElements ) do
            if permittedElement == elementType or permittedElement == elementPattern.sample then
                trueType = true
            end
        end
        if not trueType then
           error( 'Элемент "'..id..'". Элементы типа "'..elementType..'" не совместимы с модулем "..name.."' ) 
        end
        -- Проверка настроек
        local isTrueSettings, errorText = pattern.checkSettings( settings )
        if not isTrueSettings then
            if errorText then
                error( 'Элемент "'..id..'" Неверные настройки модуля"'..name..'" '..errorText )
            else
                error( 'Элемент "'..id..'" Неверные настройки модуля"'..name..'"' )
            end
        end
    end
    -- Проверка наличия требуемых модулей
    for i, requiredModule in ipairs( elementPattern.requiredModules ) do
        if not modules[ requiredModule ] then
            error( 'Элемент "'..id..'". Для модуля "'..requiredModule..'" отсутствуют требуемые модули' )
        end
    end
    -- Проверка отсутствия запрещенных модулей
    for i, incompatibleModule in ipairs( elementPattern.incompatibleModules ) do
        if modules[ incompatibleModule ] then
            error( 'Элемент "'..id..'". Присутствует запрещенный для модуля "'..requiredModule..'" модуль' )
        end
    end
end
--[[
billet = table -- заготовка элемента
{
    text = string, -- текстовое содержимое элемента
    type = string, -- тип элемента
    id = string, -- идентификатор элемента,
    attributes = table --(?) аттрибуты элемента
    {
        classes = string, --(?) css классы обертки навбокса,
        styles = string, --(?) css стили обертки навбокса,
        attrs = string --(?) HTML атрибуты обертки навбокса,
    },
    modules = table --(?) таблица модулей элемента
}
parentId = string -- идентификатор элемента, который должен быть родительским добавляемому
]]--
function navbox:_collectBillet( billet, parentId )
    local type = billet.type
    local parentElement
    if parentId then
        parentElement = self._elements[ parentId ]
    end
    if self._elementsLibrary[ type ].children then
        billet.children = {}
        if parentId and type == parentElement.type then
            billet.nesting = parentElement.nesting + 1
        else
            billet.nesting = 1
        end
    end
    if not parentId then
        billet.level = 1
        table.insert( self._elementsRoot, billet )
    else
        billet.parent =  parentElement
        billet.level = parentElement.level + 1
        table.insert( parentElement.children, billet )
    end
    self._elements[ billet.id ] = billet
end
--
function navbox:assembly()
    if self._navbox then
        error( 'Навбокс закрыт для редактирования' )
    end
    local wrapper = mw.html.create( 'div' )
    if self._attributes then
        self:_applyAttrs( wrapper, self._attributes )
    end
    wrapper:addClass( 'navbox_wrapper' )
    for i, child in ipairs( self._elementsRoot ) do
        local block = self:_assembly( child )
        wrapper:node( block )
    end
    self._navbox = wrapper
    return wrapper
end
--[[
billet = table -- заготовка элемента
{
    text = string, -- текстовое содержимое элемента
    type = string, -- тип элемента
    id = string, -- идентификатор элемента
    attributes = table --(?) аттрибуты элемента
    {
        classes = string, --(?) css классы обертки навбокса,
        styles = string --(?), css стили обертки навбокса,
        attrs = HTML атрибуты обертки навбокса,
    },
    modules = table, --(?) таблица модулей элемента
    children = table, --(?) заготовки дочерних элементов
    nesting = number, --(?) глубина вложенности в однотипные элементы
    level = number, --(?) глобальный уровень вложенности
    parent = table --(?) заготовка родительского элемента
}
]]--
function navbox:_assembly( billet )
    local text = billet.text
    local attributes = billet.attributes
    if billet.modules then
        for i, modul in ipairs( billet.modules ) do
            local attrs
            text, attrs = self._modulesLibrary[ modul._name ].modify( text, modul )
            --self:_applyAttrs( element, attributes )
        end
    end
    local childBlocks = {}
    if billet.children then
        for i, child in ipairs( billet.children ) do
            local childBlock = self:_assembly( child )
            table.insert( childBlocks, childBlock ) 
        end
    end
    element = self._elementsLibrary[ billet.type ].create( billet.text, childBlocks )
    if attributes then
        self:_applyAttrs( element, attributes )
    end
    if billet.nesting then
        element:addClass( 'navbox_'..billet.type..'_n'..billet.nesting )
    end
    return element
end
--[[
elements = table -- таблица добавляемых элементов
replace = boolean --(?) заменять ли имеющиеся элементы
]]--
function navbox:addElements( elements, replace )
    if replace and #self._elementsRoot ~= 0 then
        error( 'Замена элементов невозможна. Навбокс уже отредактирован' )
    end
    local library = self._elementsLibrary
    for name, element in pairs( elements ) do
        if replace or not library[ name ] then
            library[ name ] = element
        end
    end
end
--[[
elem = htmlObject -- элемент, к которому применяются аттрибуды
attrs = table -- применяемые аттрибуты
]]--
function navbox:_applyAttrs( elem, attrs )
    if attrs.classes then
        for i, class in ipairs( attrs.classes ) do
            elem:addClass( class )
        end 
    end
    if attrs.styles then
        elem:css( attrs.styles )
    end
    if attrs.attrs then
        elem:attr( attrs.attrs )
    end
end
--
function navbox:getBlockInfo( blockId )
    if not blockId or not self._elems[ blockId ] then
        return false
    end
    local block = self._elems[ blockId ]
    local info = {}
    info.nesting = block.nesting
    info.level = block.level
    info.blockType = block.blockType
    info.id = blockId
    if block.parent then
        info.parentId = block.parent.id
    end
    info.children = {}
    for i, child in ipairs( block.children ) do
        info.children[ #info.children + 1 ] = child.id
    end
    return info
end
--
function navbox:checkBlock( blockId )
    if blockId and self._elems[ blockId ] then
        return true
    end
    return false
end
--
function navbox:getNavbox()
    if not self._navbox then
        error( 'Навбокс не готов' )
    end
    return self._navbox
end
--
function navbox:createSection( text, id, parentId, settings )
    self:addElement( {type='section', text=text, id=id, parentId=parentId, attributes=settings} )
end
--
function navbox:createPartition( text, id, parentId, settings )
    self:addElement( {type='partition', text=text, id=id, parentId=parentId, attributes=settings} )
end
--
function navbox:createContent( text, id, parentId, settings )
    self:addElement( {type='content', text=text, id=id, parentId=parentId, attributes=settings} )
end
 --
return navbox
Advertisement