Модуль:ТранспортнаяСхема: различия между версиями

мНет описания правки
мНет описания правки
Строка 13: Строка 13:
     end
     end
      
      
     -- Способ 1: Стандартная загрузка через mw.loadJsonData (если тип контента страницы = JSON)
     -- Способ 1: mw.loadJsonData
     local success, jsonData = pcall(mw.loadJsonData, dataPageTitle)
     local success, jsonData = pcall(mw.loadJsonData, dataPageTitle)
     if success and jsonData then
     if success and jsonData then
Строка 19: Строка 19:
     end
     end
      
      
     -- Способ 2: Резервная загрузка текста и декодирование (если страница сохранена как wikitext)
     -- Способ 2: Резервная загрузка текста
     local titleObj = mw.title.new(dataPageTitle)
     local titleObj = mw.title.new(dataPageTitle)
     if titleObj and titleObj.exists then
     if titleObj and titleObj.exists then
         local rawText = titleObj:getContent()
         local rawText = titleObj:getContent()
         if rawText and rawText ~= '' then
         if rawText and rawText ~= '' then
            -- Очистка от возможных noinclude / комментариев
             rawText = mw.ustring.gsub(rawText, '<noinclude>.-</noinclude>', '')
             rawText = mw.ustring.gsub(rawText, '<noinclude>.-</noinclude>', '')
             rawText = mw.ustring.gsub(rawText, '<!--.--->', '')
             rawText = mw.ustring.gsub(rawText, '<!--.--->', '')
Строка 81: Строка 80:


     local jsonData = loadData(frame)
     local jsonData = loadData(frame)
    local isInfobox = (args['карточка'] == 'да' or args['тип'] == 'карточка' or frame.args['карточка'] == 'да')
   
    local defaultWidth = isInfobox and '280px' or '850px'
     local imageFile = args['файл'] or jsonData.image or 'Схема_Муроморского_метрополитена.png'
     local imageFile = args['файл'] or jsonData.image or 'Схема_Муроморского_метрополитена.png'
     local width = args['ширина'] or jsonData.width or '850px'
     local width = args['ширина'] or (not isInfobox and jsonData.width) or defaultWidth
     local caption = args['подпись'] or jsonData.caption or 'Интерактивная схема линий Муроморска'
     local caption = args['подпись'] or jsonData.caption or ''
     local defaultRadius = args['радиус'] or jsonData.defaultRadius or '16'
     local defaultRadius = args['радиус'] or jsonData.defaultRadius or '16'
      
      
Строка 89: Строка 91:
         :addClass('ts-transport-scheme')
         :addClass('ts-transport-scheme')
         :css({
         :css({
             ['clear'] = 'both',
             ['clear'] = isInfobox and 'none' or 'both',
             ['margin'] = '1.2em auto',
             ['margin'] = isInfobox and '0 auto' or '1.2em auto',
             ['width'] = '100%',
             ['width'] = '100%',
             ['text-align'] = 'center'
             ['text-align'] = 'center'
Строка 99: Строка 101:
         :addClass('ts-transport-map-card')
         :addClass('ts-transport-map-card')
         :css({
         :css({
             ['display'] = 'inline-block',
             ['display'] = isInfobox and 'block' or 'inline-block',
             ['max-width'] = '100%',
             ['max-width'] = '100%',
             ['background'] = 'var(--background-color-base, #ffffff)',
             ['background'] = isInfobox and 'transparent' or 'var(--background-color-base, #ffffff)',
             ['border'] = '1px solid var(--border-color-base, #d0d7de)',
             ['border'] = isInfobox and 'none' or '1px solid var(--border-color-base, #d0d7de)',
             ['border-radius'] = '10px',
             ['border-radius'] = isInfobox and '0' or '10px',
             ['padding'] = '10px',
             ['padding'] = isInfobox and '0' or '10px',
             ['box-shadow'] = '0 3px 12px rgba(0,0,0,0.06)'
             ['box-shadow'] = isInfobox and 'none' or '0 3px 12px rgba(0,0,0,0.06)'
         })
         })


     local mapContainer = mapCard:tag('div')
     local mapContainer = mapCard:tag('div')
         :css({ ['overflow-x'] = 'auto', ['max-width'] = '100%' })
         :css({
            ['overflow-x'] = 'auto',
            ['max-width'] = '100%',
            ['text-align'] = 'center'
        })


     local imageMapContent = buildImageMap(jsonData, imageFile, width, defaultRadius)
     local imageMapContent = buildImageMap(jsonData, imageFile, width, defaultRadius)
     mapContainer:wikitext(frame:preprocess('{{#tag:imagemap|' .. imageMapContent .. '}}'))
     mapContainer:wikitext(frame:preprocess('{{#tag:imagemap|' .. imageMapContent .. '}}'))


     if caption ~= '' then
     if caption ~= '' and not isInfobox then
         mapCard:tag('div')
         mapCard:tag('div')
             :css({
             :css({
Строка 126: Строка 132:
     end
     end


     -- 2. Легенда линий
     -- В режиме карточки (инфобокса) скрываем громоздкую легенду и реестр
    if jsonData.lines and #jsonData.lines > 0 then
    if not isInfobox then
        local legend = root:tag('div')
        -- 2. Легенда линий
            :addClass('ts-transport-lines-legend')
        if jsonData.lines and #jsonData.lines > 0 then
            :css({
            local legend = root:tag('div')
                ['margin'] = '12px auto',
                :addClass('ts-transport-lines-legend')
                ['max-width'] = '950px',
                :css({
                ['padding'] = '8px 12px',
                    ['margin'] = '12px auto',
                ['background'] = '#f6f8fa',
                    ['max-width'] = '950px',
                ['border'] = '1px solid #d0d7de',
                    ['padding'] = '8px 12px',
                ['border-radius'] = '8px'
                    ['background'] = '#f6f8fa',
            })
                    ['border'] = '1px solid #d0d7de',
                    ['border-radius'] = '8px'
                })


        legend:tag('div')
             legend:tag('div')
            :css({
                ['font-size'] = '11px',
                ['font-weight'] = 'bold',
                ['color'] = '#57606a',
                ['text-transform'] = 'uppercase',
                ['margin-bottom'] = '6px',
                ['letter-spacing'] = '0.5px'
             })
            :wikitext(jsonData.legendTitle or 'Линии скоростного транспорта')
 
        local legendBadges = legend:tag('div')
            :css({
                ['display'] = 'flex',
                ['flex-wrap'] = 'wrap',
                ['justify-content'] = 'center',
                ['gap'] = '5px'
            })
 
        for _, line in ipairs(jsonData.lines) do
            local badge = legendBadges:tag('span')
                 :css({
                 :css({
                     ['display'] = 'inline-flex',
                     ['font-size'] = '11px',
                     ['align-items'] = 'center',
                     ['font-weight'] = 'bold',
                     ['padding'] = '2px 8px 2px 4px',
                     ['color'] = '#57606a',
                    ['background'] = '#ffffff',
                     ['text-transform'] = 'uppercase',
                     ['border'] = '1px solid #d0d7de',
                     ['margin-bottom'] = '6px',
                     ['border-radius'] = '20px',
                     ['letter-spacing'] = '0.5px'
                     ['font-size'] = '12px'
                 })
                 })
                :wikitext(jsonData.legendTitle or 'Линии скоростного транспорта')


             badge:tag('span')
             local legendBadges = legend:tag('div')
                 :css({
                 :css({
                     ['display'] = 'inline-flex',
                     ['display'] = 'flex',
                     ['align-items'] = 'center',
                     ['flex-wrap'] = 'wrap',
                     ['justify-content'] = 'center',
                     ['justify-content'] = 'center',
                     ['min-width'] = '16px',
                     ['gap'] = '5px'
                    ['height'] = '16px',
                    ['padding'] = '0 4px',
                    ['border-radius'] = '999px',
                    ['background-color'] = line.color or '#888888',
                    ['color'] = line.textColor or '#ffffff',
                    ['font-size'] = '9.5px',
                    ['font-weight'] = 'bold',
                    ['margin-right'] = '6px'
                 })
                 })
                :wikitext(line.symbol or line.number or '•')


             badge:tag('span')
             for _, line in ipairs(jsonData.lines) do
                 :wikitext('[[' .. (line.article or '') .. '|' .. (line.displayName or line.name or line.article or '') .. ']]')
                local badge = legendBadges:tag('span')
                    :css({
                        ['display'] = 'inline-flex',
                        ['align-items'] = 'center',
                        ['padding'] = '2px 8px 2px 4px',
                        ['background'] = '#ffffff',
                        ['border'] = '1px solid #d0d7de',
                        ['border-radius'] = '20px',
                        ['font-size'] = '12px'
                    })
 
                 badge:tag('span')
                    :css({
                        ['display'] = 'inline-flex',
                        ['align-items'] = 'center',
                        ['justify-content'] = 'center',
                        ['min-width'] = '16px',
                        ['height'] = '16px',
                        ['padding'] = '0 4px',
                        ['border-radius'] = '999px',
                        ['background-color'] = line.color or '#888888',
                        ['color'] = line.textColor or '#ffffff',
                        ['font-size'] = '9.5px',
                        ['font-weight'] = 'bold',
                        ['margin-right'] = '6px'
                    })
                    :wikitext(line.symbol or line.number or '•')
 
                badge:tag('span')
                    :wikitext('[[' .. (line.article or '') .. '|' .. (line.displayName or line.name or line.article or '') .. ']]')
            end
         end
         end
    end


    -- 3. Каталог станций
        -- 3. Каталог станций
    if jsonData.lines and #jsonData.lines > 0 then
        if jsonData.lines and #jsonData.lines > 0 then
        local listCard = root:tag('div')
            local listCard = root:tag('div')
            :addClass('mw-collapsible toccolours')
                :addClass('mw-collapsible toccolours')
            :css({
                :css({
                ['margin'] = '12px auto 0 auto',
                    ['margin'] = '12px auto 0 auto',
                ['max-width'] = '950px',
                    ['max-width'] = '950px',
                ['text-align'] = 'left',
                    ['text-align'] = 'left',
                ['background'] = 'var(--background-color-neutral-subtle, #f8f9fa)',
                    ['background'] = 'var(--background-color-neutral-subtle, #f8f9fa)',
                ['border'] = '1px solid var(--border-color-base, #d0d7de)',
                    ['border'] = '1px solid var(--border-color-base, #d0d7de)',
                ['border-radius'] = '8px',
                    ['border-radius'] = '8px',
                ['overflow'] = 'hidden'
                    ['overflow'] = 'hidden'
            })
                })


        listCard:tag('div')
            listCard:tag('div')
            :css({
                :css({
                ['font-weight'] = 'bold',
                    ['font-weight'] = 'bold',
                ['font-size'] = '13.5px',
                    ['font-size'] = '13.5px',
                ['background'] = 'linear-gradient(180deg, #f6f8fa 0%, #eaeef2 100%)',
                    ['background'] = 'linear-gradient(180deg, #f6f8fa 0%, #eaeef2 100%)',
                ['padding'] = '9px 14px',
                    ['padding'] = '9px 14px',
                ['border-bottom'] = '1px solid var(--border-color-base, #d0d7de)'
                    ['border-bottom'] = '1px solid var(--border-color-base, #d0d7de)'
            })
                })
            :wikitext(jsonData.listTitle or '📋 Реестр станций метрополитена и МЖД')
                :wikitext(jsonData.listTitle or '📋 Реестр станций метрополитена и МЖД')


        local listContent = listCard:tag('div')
            local listContent = listCard:tag('div')
            :addClass('mw-collapsible-content')
                :addClass('mw-collapsible-content')
            :css({
                :css({
                ['padding'] = '14px 18px',
                    ['padding'] = '14px 18px',
                ['column-width'] = '20em',
                    ['column-width'] = '20em',
                ['column-gap'] = '2em',
                    ['column-gap'] = '2em',
                ['column-rule'] = '1px solid #e1e4e8',
                    ['column-rule'] = '1px solid #e1e4e8',
                ['font-size'] = '13px',
                    ['font-size'] = '13px',
                ['line-height'] = '1.7'
                    ['line-height'] = '1.7'
            })
                })


        local currentMode = nil
            local currentMode = nil
        local listWikitext = ''
            local listWikitext = ''


        for _, line in ipairs(jsonData.lines) do
            for _, line in ipairs(jsonData.lines) do
            local mode = line.mode or 'other'
                local mode = line.mode or 'other'
            if mode ~= currentMode then
                if mode ~= currentMode then
                currentMode = mode
                    currentMode = mode
                listWikitext = listWikitext .. "\n; " .. getModeLabel(mode) .. "\n"
                    listWikitext = listWikitext .. "\n; " .. getModeLabel(mode) .. "\n"
            end
                end


            listWikitext = listWikitext .. "* '''[[" .. (line.article or '') .. '|' .. (line.name or line.article or '') .. "]]'''\n"
                listWikitext = listWikitext .. "* '''[[" .. (line.article or '') .. '|' .. (line.name or line.article or '') .. "]]'''\n"
            for _, station in ipairs(line.stations or {}) do
                for _, station in ipairs(line.stations or {}) do
                local badge = "<span style='display:inline-flex;align-items:center;justify-content:center;min-width:14px;height:14px;padding:0 3px;border-radius:999px;background:" .. (line.color or '#888') .. ";color:" .. (line.textColor or '#fff') .. ";font-size:9px;font-weight:bold;margin-right:4px;'>" .. (line.symbol or line.number or '•') .. "</span>"
                    local badge = "<span style='display:inline-flex;align-items:center;justify-content:center;min-width:14px;height:14px;padding:0 3px;border-radius:999px;background:" .. (line.color or '#888') .. ";color:" .. (line.textColor or '#fff') .. ";font-size:9px;font-weight:bold;margin-right:4px;'>" .. (line.symbol or line.number or '•') .. "</span>"
                listWikitext = listWikitext .. '** ' .. badge .. ' [[' .. station.article .. '|' .. (station.name or station.article) .. ']]'
                    listWikitext = listWikitext .. '** ' .. badge .. ' [[' .. station.article .. '|' .. (station.name or station.article) .. ']]'
                if station.transfer then
                    if station.transfer then
                    listWikitext = listWikitext .. " <small style='color:#57606a;'>(" .. station.transfer .. ")</small>"
                        listWikitext = listWikitext .. " <small style='color:#57606a;'>(" .. station.transfer .. ")</small>"
                    end
                    if station.future then
                        listWikitext = listWikitext .. " <small style='color:#8c959f; font-style:italic;'>(строит.)</small>"
                    end
                    listWikitext = listWikitext .. '\n'
                 end
                 end
                if station.future then
                    listWikitext = listWikitext .. " <small style='color:#8c959f; font-style:italic;'>(строит.)</small>"
                end
                listWikitext = listWikitext .. '\n'
             end
             end
            listContent:wikitext(listWikitext)
         end
         end
        listContent:wikitext(listWikitext)
     end
     end