跳转到内容

模組:Taxobox/Sandbox

维基百科,自由的百科全书

这是本页的一个历史版本,由Fantasticfears留言 | 贡献2013年9月13日 (五) 17:43编辑。这可能和当前版本存在着巨大的差异。

--
-- This module implements {{Taxobox}}
--

local p = {}

local HtmlBuilder = require('Module:HtmlBuilder')
local Symbol = require('Module:TaxoboxSymbol')

local backgroundColor = '#f9f9f9'
local args = {}
local origArgs
local root
local lastAuthority

local function preprocessSingleArg(argName)
    -- If the argument exists and isn't blank, add it to the argument table.
    -- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
    if origArgs[argName] and origArgs[argName] ~= '' then
        args[argName] = origArgs[argName]
    end
end

local function preprocessArgs(mainArg, subArgsTable, step)
    if not mainArg then return end
    if type(step) ~= 'number' then
        error("Invalid step value detected", 2)
    end

    -- Add postfix 1 to argument
    if origArgs[mainArg] then
        origArgs[mainArg .. '1'] = origArgs[mainArg]
    end
    for i, v in ipairs(subArgsTable) do
        local argName = mainArg .. '_' .. v
        if origArgs[argName] then
            origArgs[mainArg .. '1_' .. v] = origArgs[argName]
        end
    end

    for i = 1, step do
        local prefixArgName = mainArg .. tostring(i)
        preprocessSingleArg(prefixArgName)
        for j, v in ipairs(subArgsTable) do
            local argName = prefixArgName .. '_' .. v
            if origArgs[argName] then
                preprocessSingleArg(argName)
            end
        end
    end
end

local function preprocessClassificationArgs()
    local c = Symbol.classificationTable

    for i = 1, #c do
        local arg = c[i]['argName']
        preprocessSingleArg('unranked_' .. arg)
        preprocessSingleArg('unranked_' .. arg .. '_local')
        preprocessSingleArg('unranked_' .. arg .. '_authority')
        preprocessSingleArg(arg)
        preprocessSingleArg(arg .. '_local')
        preprocessSingleArg(arg .. '_authority')
    end
end

local function preprocessTypeSpeciesArgs()
    local t = Symbol.typeSpeciesTable

    for i = 1, #t do
        local arg = 'type_' .. t[i]['argPostfix']
        preprocessSingleArg(arg)
        preprocessSingleArg(arg .. '_authority')
    end
end

local function getArgNums(prefix)
    -- Returns a table containing the numbers of the arguments that exist
    -- for the specified prefix. For example, if the prefix was 'data', and
    -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
    local nums = {}
    for k, v in pairs(args) do
        local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
        if num then table.insert(nums, tonumber(num)) end
    end
    table.sort(nums)
    return nums
end

local function getClassificationEntry()
    local c = Symbol.classificationTable

    local entryTable = {}
    for i = 1, #c do
        local argName = c[i]['argName']

        for j, v in ipairs({'unranked_' .. argName, argName}) do
            if j == 1 then
                if args[v] then
                    table.insert(entryTable, {
                        ['id'] = i, ['argName'] = v, ['entryName'] = '(未分级)',
                        ['className'] = 'unranked'})
                end
            else
                if args[v] then
                    table.insert(entryTable, {
                        ['id'] = i, ['argName'] = v, ['entryName'] = c[i]['entryName'] .. ':',
                        ['className'] = c[i]['className'] or c[i]['argName']})
                end
            end
        end
    end

    return entryTable
end

local function getBackgroundColor()
    if args.color then
        return args.color
    end

    local arg
    if args.domain and args.domain:lower():find('bacteria') ~= nil then
        arg = 'bacteria'
    else
        arg = (args.regnum or args.virus_group or args.unranked_phylum or args.unranked_phylum or
              args.unranked_superdivisio or args.phylum):lower()
    end

    if arg:find('animal') ~= nil then
        return '#d3d3a4;'
    elseif arg:find('plant') ~= nil or arg:find('archaeplastida') ~= nil then
        return '#90ee90;'
    elseif arg:find('fungi') ~= nil or arg:find('fungus') ~= nil then
        return '#add8e6;'
    elseif arg:find('chromalveolata') ~= nil or arg:find('chromalveolate') ~= nil then
        return '#adee3f;'
    elseif arg:find('choanozoa') ~= nil or arg:find('opisthokonta') ~= nil then
        return '#e0d0b0;'
    elseif arg:find('rhizaria') ~= nil then
        return '#e1ccfc;'
    elseif arg:find('excavata') ~= nil or arg:find('excavate') ~= nil or arg:find('protist') ~= nil then
        return '#f0e68c;'
    elseif arg:find('amoebozoa') ~= nil then
        return '#ffc8a0;'
    elseif arg:find('bacteria') ~= nil or arg:find('bacterium') ~= nil or arg:find('firmicutes') ~= nil then
        return '#d3d3d3;'
    elseif arg:find('nanoarchaeota') ~= nil or arg:find('nanarchaeota') ~= nil or
           arg:find('korarchaeota') ~= nil or arg:find('archaea') ~= nil or
           arg:find('thaumarchaeota') ~= nil or arg:find('crenarchaeota') ~= nil or 
           arg:find('euryarchaeota') ~= nil then
        return '#ecd2d2;'
    elseif arg:find('incertae sedis') ~= nil then
        return '#faf0e6;'
    elseif arg:find('virus') ~= nil or arg == 'i' or arg == 'ii' or arg == 'iii' or
           arg == 'iv' or arg == 'v' or arg =='vi' or arg == 'vii' or arg == 'viii' then
        return '#ee82ee;'
    else
        if mw.site.namespaces.id == 0 then
            root.wikitext('[[Category:未指定Taxobox模板颜色]]')
        end
        return 'transparent; text-align: center; border: 1px solid red;'
    end
end

local function renderHeader()
    if not args.name then return end
 
    local header = root.tag('tr')
        .css('text-align', 'center')
        .css('background-color', backgroundColor)
        .tag('th')
            .attr('colspan', 2)
            .css('vertical-align', 'middle')
            .css('height', '25px')
            .tag('div')
                .css('position', 'absolute')
                .css('right', '6px')
                .addClass('floatright')
                .tag('span')
                    .addClass('metadata')
                    .wikitext('[[File:Torchlight_help_icon.svg|16px|alt=如何讀生物分類框|link=Wikipedia:如何讀生物分類框|如何讀生物分類框]]')
                    .done()
                .done()
            .wikitext(args.name)

    if args.fossil_range then
        header.tag('br').tag('small').wikitext('化石時期:' .. args.fossil_range)
    end
end

local function renderImages()
    local imageNums = getArgNums('image')
    for k, num in ipairs(imageNums) do
        local prefix = 'image' .. tostring(num)
        local data = '[[File:' .. args[prefix]

        if args[prefix .. '_width'] then
            data = data .. '|' .. args[prefix .. '_width']
        else
            data = data .. '|frameless'
        end
        if args[prefix .. '_alt'] then
            data = data .. '|alt=' .. args[prefix .. '_alt']
        end
        data = data .. ']]'

        root.tag('tr').tag('td')
            .attr('colspan', 2)
            .css('text-align', 'center')
            .wikitext(data)
        if args[prefix .. '_caption'] then
            root.tag('tr').tag('td')
                .attr('colspan', 2)
                .css('text-align', 'center')
                .css('font-size', '88%')
                .wikitext(args[prefix .. '_caption'])
        end
    end
end

local function renderConservationStatus()
    local statusnums = getArgNums('status')
    if not statusnums then return end

    local s = Symbol.conservationStatusTable

    root.tag('tr').tag('th')
        .attr('colspan', 2)
        .css('text-align', 'center')
        .css('background-color', backgroundColor)
        .wikitext('[[保护状况]]')

    for k, num in ipairs(statusnums) do
        local prefix = 'status' .. tostring(num)
        local system = (args[prefix .. '_system'] or 'default'):lower()
        local status = (args[prefix] or 'invaild'):lower()

        if not s[system] then
            system = 'default'
        elseif s[system]['alias'] then
            system = s[system]['alias']
        end
        if not s[system][status] then
            status = 'invalid'
        elseif s[system][status]['alias'] then
            status = s[system][status]['alias']
        end

        local element = root.tag('tr').tag('td')
            .attr('colspan', 2)
            .tag('div')
        if s[system][status]['photo'] then
            element
                .wikitext(s[system][status]['photo'])
                .tag('br')
        end
        element
            .css('text-align', 'center')
            .wikitext(s[system][status]['name'])
        if s[system][status]['extinct'] and args.extinct then
            element.wikitext('(' .. args.extinct .. ')')
        end

        element.tag('span')
            .css('font-size', '0.8em')
            .wikitext('(' .. (args.status_text or s[system]['introduction']) ..  ')' ..
                      (args[prefix .. '_ref'] or ''))

        if s[system][status]['category'] and mw.site.namespaces.id == 0 then
            element.wikitext('[[Category:' .. s[system][status]['category'] .. ']]')
        end
    end
end

local function renderClassification()
    local header = root.tag('tr').tag('th')
        .attr('colspan', 2)
        .css('text-align', 'center')
        .css('background-color', backgroundColor)
        .wikitext(args.virus_group and '[[病毒分類]]' or '[[科學分類]]')

    local row = root.tag('tr')
    if args.virus_group then
        root.tag('td').wikitext('组')

        args.virus_group = args.virus_group:lower()
        local text
        if args.virus_group == 'i' then
            text = 'Group I<small>([[dsDNA病毒|dsDNA]])</small>'
        elseif args.virus_group == 'ii' then
            text = 'Group II<small>([[ssDNA病毒|ssDNA]])</small>'
        elseif args.virus_group == 'iii' then
            text = 'Group III<small>([[dsRNA病毒|dsRNA]])</small>'
        elseif args.virus_group == 'iv' then
            text = 'Group IV<small>([[正義ssRNA病毒|(+)ssRNA]])</small>'
        elseif args.virus_group == 'v' then
            text = 'Group V<small>([[反義ssRNA病毒|(-)ssRNA]])</small>'
        elseif args.virus_group == 'vi' then
            text = 'Group VI<small>([[ssRNA-RT病毒|ssRNA-RT]])</small>'
        elseif args.virus_group == 'vii' then
            text = 'Group VII<small>([[dsDNA-RT病毒|dsDNA-RT]])</small>'
        else
            text = args.virus_group
        end
        root.tag('td').wikitext(text)

        return
    end

    local entrys = getClassificationEntry()
    for i = 1, #entrys do
        local argName = entrys[i]['argName']
        local entryName = entrys[i]['entryName']
        local id = entrys[i]['id']

        local localText = args[argName .. '_local'] or ''
        if localText and i ~= #entrys then
            localText = '[[' .. localText .. ']]'
        end
        local text = args[argName]
        if tonumber(id) >= 35 then -- genus
            text = '\'\'' .. args[argName] .. '\'\''
        end

        text = localText .. ' ' .. text
        if i == #entrys then -- last entry
            text = '\'\'\'' .. text .. '\'\'\'' 
        end

        local row = root.tag('tr')
        row.tag('td').css('text-align', 'left').css('white-space', 'nowrap').wikitext(entryName)

        local cell = row.tag('td').tag('span')
        cell
            .addClass(className)
            .css('white-space', 'nowrap')
            .wikitext(text)
        if args[argName .. '_authority'] then
            cell.tag('br')
            cell.tag('small').wikitext(args[argName .. '_authority'])
        end
    end
end

local function renderNomenclature()
    if args.binomial1 then
        local cell = root
            .tag('tr')
                .tag('th')
                    .attr('colspan', 2)
                    .css('text-align', 'center')
                    .css('background-color', backgroundColor)
                    .wikitext('[[二名法]]')
                    .done()
                .done()
            .tag('tr')
                .tag('td')
                    .attr('colspan', 2)
                    .css('text-align', 'center')
                    .tag('span')
                        .addClass('binomial')
                        .css('font-weight', 'bold')
                        .wikitext(args.binomial1)
                        .done()
        if args.binomial1_authority then
            cell.tag('br').tag('small').wikitext(args.binomial1_authority)
        end
    end

    if args.trinomial1 then
        local tip = '[[三名法]]'
        if args.regnum and args.regnum:lower():find('plant') ~= nil or
           args.regnum:lower():find('archaeplastida') ~= nil then
            tip = '[[種下分類群|三名法]]'
        end

        local cell = root
            .tag('tr')
                .tag('th')
                    .attr('colspan', 2)
                    .css('text-align', 'center')
                    .css('background-color', backgroundColor)
                    .wikitext(tip)
                    .done()
                .done()
            .tag('tr')
                .tag('td')
                    .attr('colspan', 2)
                    .css('text-align', 'center')
                    .tag('span')
                        .addClass('trinomial')
                        .css('font-weight', 'bold')
                        .wikitext(args.binomial1)
                        .done()
        if args.trinomial1_authority then
            cell.tag('br').tag('small').wikitext(args.trinomial1_authority)
        end
    end
end

local function renderTypeSpecies()
    local t = Symbol.typeSpeciesTable

    for i = 1, #t do
        local argName = 'type_' .. t[i]['argPostfix']
        if args[argName] then
            local cell = root
                .tag('tr')
                    .tag('th')
                        .attr('colspan', 2)
                        .css('text-align', 'center')
                        .css('background-color', backgroundColor)
                        .wikitext(t[i]['entryText'])
                        .done()
                    .done()
                .tag('tr')
                    .tag('td')
                        .attr('colspan', 2)
                        .css('text-align', 'center')
                        .wikitext(args[argName])
                        .done()
            if args[argName .. '_authority'] then
                cell.tag('br').tag('small').wikitext(args[argName .. '_authority'])
            end
        end
    end
end

local function renderSubdivision()
    if args.subdivision then
        root.tag('tr')
            .tag('td')
                .attr('colspan', 2)
                .css('text-align', 'center')
                .css('background-color', backgroundColor)
                .wikitext(args.subdivision_ranks or '')
                .done()
            .tag('td')
                .attr('colspan', 2)
                .css('text-align', 'left')
                .wikitext(args.subdivision)
    end

    if args.possible_subdivision then
        root.tag('tr')
            .tag('td')
                .attr('colspan', 2)
                .css('text-align', 'center')
                .css('background-color', backgroundColor)
                .wikitext(args.possible_subdivision_ranks or '')
                .done()
            .tag('td')
                .attr('colspan', 2)
                .css('text-align', 'left')
                .wikitext(args.possible_subdivision)
    end
end

local function renderDiversity()
    if not args.diversity or not args.diversity_link then return end
    root.tag('tr')
        .tag('td')
            .attr('colspan', 2)
            .css('text-align', 'center')
            .css('background-color', backgroundColor)
            .wikitext('[[' .. args.diversity_link .. '|多样性]]')
            .done()
        .tag('td')
            .attr('colspan', 2)
            .css('text-align', 'center')
            .wikitext(args.diversity)
    if mw.site.namespaces.id == 0 then
        root.wikitext('[[Cagegory:使用多样性参数的Taxobox]]')
    end
end

local function renderRangeMapAndExtraNomenclature()
    local prefix

    for i = 1, 4 do
        if i ~= 1 then
            for k, name in ipairs({'binomial', 'trinomial'}) do
                prefix = name .. i

                if args[prefix] then
                    local cell = root.tag('tr').tag('td')
                        .attr('colspan', 2)
                        .css('text-align', 'center')
                        .wikitext('\'\'\'' .. args[prefix] .. '\'\'\'')
                    if args[prefix .. '_authority'] then
                        cell.tag('small').wikitext(args[prefix .. '_authority'])
                    end
                end
            end
        end

        prefix = 'range_map' .. i
        if args[prefix] then
            root.tag('tr').tag('td')
                .attr('colspan', 2)
                 .css('text-align', 'center')
                 .wikitext('[[File:' .. args[prefix],
                           '|' .. (args[prefix .. '_width'] or 'frameless'),
                           '|alt=' .. (args[prefix .. '_alt'] or ''), ']]')
            root.tag('tr').tag('td')
                .attr('colspan', 2)
                .css('text-align', 'center')
                .css('font-size', '88%')
                .wikitext(args[prefix .. '_caption'])
        end
    end
end

local function renderSynonyms()
    if not args.synonyms then return end

    root.tag('tr').tag('td')
        .attr('colspan', 2)
        .css('text-align', 'center')
        .css('background-color', backgroundColor)
        .wikitext('[[異名]]' .. (args.synonyms_ref or ''))
    root.tag('tr').tag('td')
        .attr('colspan', 2)
        .css('text-align', 'left')
        .wikitext(args.synonyms)
end

local function renderFooter()
    if not args.footer then return end

    root.tag('tr').tag('td')
        .attr('colspan', 2)
        .css('text-align', 'left')
        .wikitext(args.footer)
end

local function _taxobox()
    backgroundColor = getBackgroundColor()

    root = HtmlBuilder.create('table')

    root
        .addClass('infobox')
        .addClass('biota')
        .css('text-align', 'left')
        .css('width', '200px')
        .css('font-size', '100%')

    renderHeader()
    renderImages()
    renderConservationStatus()
    renderClassification()
    renderNomenclature()
    renderTypeSpecies()
    renderSubdivision()
    renderDiversity()
    renderRangeMapAndExtraNomenclature()
    renderSynonyms()
    renderFooter()

    return tostring(root)
end

function p.taxobox(frame)
    -- If called via #invoke, use the args passed into the invoking template.
    -- Otherwise, for testing purposes, assume args are being passed directly in.
    if frame == mw.getCurrentFrame() then
        origArgs = frame:getParent().args
    else
        origArgs = frame
    end

    -- Parse the data parameters in the same order that the old {{taxobox}} did, so that
    -- references etc. will display in the expected places. Parameters that depend on
    -- another parameter are only processed if that parameter is present, to avoid
    -- phantom references appearing in article reference lists.
    preprocessSingleArg('color')
    preprocessSingleArg('name')
    preprocessArgs('status', {'system', 'ref'}, 3)
    preprocessSingleArg('status_text')
    preprocessSingleArg('extinct')
    preprocessSingleArg('fossil_range')
    preprocessArgs('image', {'width', 'alt', 'caption'}, 3)
    preprocessSingleArg('classification_status')
    preprocessSingleArg('virus')
    preprocessSingleArg('virus_group')
    preprocessClassificationArgs()
    preprocessArgs('binomial', {'authority'}, 4)
    preprocessArgs('trinomial', {'authority'}, 4)
    preprocessTypeSpeciesArgs()
    preprocessSingleArg('subdivision')
    preprocessSingleArg('subdivision_ranks')
    preprocessSingleArg('possible_subdivision')
    preprocessSingleArg('possible_subdivision_ranks')
    preprocessSingleArg('diversity')
    preprocessSingleArg('diversity_link')
    preprocessArgs('range_map', {'width', 'alt', 'caption'}, 4)
    preprocessSingleArg('synonyms')
    preprocessSingleArg('synonyms_ref')
    preprocessSingleArg('footer')

    return _taxobox()
end

return p