Module:Icon list

From Little-Known Galaxy Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Icon list/doc

local p = {}
local lib = require('Module:Feature')
local Icon = require('Module:Icon')._main

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		parentFirst = true,
		removeBlanks = false,
		wrapper = { 'Template:Icon list' }
	})
	return p._main(args)
end

function p._main(args)
	local input = args[1] or ''
	local itemDelim = args.delim or ';'
	local items = lib.split(input, itemDelim)
	if next(items) == nil then
		return mw.html.create('span')
	else
		return p.buildList(items, args)
	end
end

local function splitNote(entry, notePattern)
	if notePattern then
		local item, note = entry:match(notePattern)
		if item == nil then -- will be nil if note is not present
			return entry
		end
		return item, note
	end
	return entry
end

local function splitParams(entry, paramDelim)
	if entry:find('{.-}') then
		local params = string.match(entry, '{(.-)}')
		entry = entry:gsub('{.-}', '')
		params = lib.split(params, paramDelim)
		local returns = {}
		for i, param in ipairs(params) do
			local name, val = string.match(param, '^%s*(.-)%s*=%s*(.-)%s*$')
			if name ~= nil and name ~= '' and val ~= nil then --named params
				returns[name] = val
			elseif param ~= nil and param ~= '' then --unnamed params
				table.insert(returns, param)
			end
		end
		return entry, returns
	end
	return entry, {}
end

function p.buildList(items, args)
	local countDelim = args.amount_delim or '*'
	local qualityDelim = args.quality_delim or '/'
	local paramDelim = args.param_delim or '$'
	local noteDelim = args.note_delim or '»'
    local textPrefixDelim = args.text_prefix_delim or '«'
	
	-- put all text after the first noteDelim into the second capture
	local notePattern
	if lib.isNotEmpty(noteDelim) then
		notePattern = '^(.-)' .. noteDelim .. '(.*)$'
	end
	
	local display = args.display or 'stacked'
	local remove = args.remove or ''
	local useColumns = args.col == 'true' and true or false

	local itemStrings = {}
	for i, str in ipairs(items) do
		if not lib.isEmpty(str) then
			for num, entry in ipairs(lib.split(str, '//')) do
				local entry, iconArgs = splitParams(entry, paramDelim) --check for entry-specific params
				
				local pre, note = splitNote(entry, notePattern) --check for entry-specific note
				
				local pre_parts = lib.split(pre, qualityDelim) --check for entry-specific note
				local item = pre_parts[1]
				local quality = pre_parts[2]
				
				local item_parts = lib.split(item, countDelim) --check for entry-specific amount
				local text_prefix_parts = lib.split(item_parts[1], textPrefixDelim) -- check for entry-specific prefix

                local textPrefix = text_prefix_parts[2]
                -- prefix is a text modifier only, so the link should not include it
                local name = text_prefix_parts[1]
				local amount = item_parts[2]
				
				--set icon arguments without replacing those set by entry-specific params
				iconArgs.name			= iconArgs[1]				or iconArgs.name		or name
				iconArgs.amount			= iconArgs.amount			or iconArgs[2]			or amount or args.amount or args[2]
				iconArgs.note			= iconArgs.note				or note
				iconArgs.q				= iconArgs.quality			or quality				or args.quality
				iconArgs.text			= iconArgs.text				or args.text
				iconArgs.textPrefix     = iconArgs.textPrefix       or args.textPrefix      or textPrefix
                iconArgs.size			= iconArgs.size				or args.size
				iconArgs.link			= iconArgs.link				or args.link            or link
				iconArgs.ext			= iconArgs.ext				or args.ext
				iconArgs.notext			= iconArgs.notext			or args.notext
				iconArgs.nolink			= iconArgs.nolink			or args.nolink
				iconArgs.prefix			= iconArgs.prefix			or args.prefix
				iconArgs.suffix			= iconArgs.suffix			or args.suffix
				
				local icon = Icon(iconArgs)
				if remove == 'text' then
					iconArgs.notext = true
					icon = Icon(iconArgs)
				elseif remove == 'link' then
					iconArgs.nolink = true
					icon = Icon(iconArgs)
				end
				table.insert(itemStrings, tostring(icon))
			end
		end
	end

	if display == 'stacked' then
		return p.displayStacked(itemStrings, useColumns)
	elseif display == 'ul' or display == 'bullet' then
		return p.displayBullet(itemStrings, useColumns)
	elseif display == 'checkbox' then
		return p.displayCheckbox(itemStrings, useColumns, args.checklistId)
	elseif display == 'inline' then
		return p.displayInline(itemStrings)
	elseif display == 'inline and' then
		return p.displayInlineAnd(itemStrings)
	elseif display == 'inline or' then
		return p.displayInlineOr(itemStrings)
	else
		return p.displayStacked(itemStrings, useColumns)
	end
end

function p.createColumns(items, useColumns)
    local columnContainer = mw.html.create('div')
    if useColumns then
        columnContainer:css({
            ['column-gap'] = '1em',
            ['column-width'] = '220px',
            ['-moz-column-count'] = 'auto',
            ['-webkit-column-count'] = 'auto',
            ['column-count'] = 'auto'
        })
    end

    for _, item in ipairs(items) do
        columnContainer:node(item)
    end
    
    return columnContainer
end

function p.displayStacked(itemStrings, useColumns)
    local itemContainers = {}
    for _, itemString in ipairs(itemStrings) do
        table.insert(itemContainers, mw.html.create('div'):wikitext(itemString))
    end
    if useColumns then
        return tostring(p.createColumns(itemContainers, useColumns))
    else
        local container = mw.html.create('div'):addClass('icon-list-stacked')
        for _, itemContainer in ipairs(itemContainers) do
            container:node(itemContainer)
        end
        return tostring(container)
    end
end

function p.displayBullet(itemStrings, useColumns)
    local list = mw.html.create('ul')
    for _, itemString in ipairs(itemStrings) do
        list:tag('li'):wikitext(itemString)
    end
    if useColumns then
        return tostring(p.createColumns({list}, useColumns))
    else
        return tostring(list)
    end
end

function p.displayCheckbox(itemStrings, useColumns, checklistId)
    local container = mw.html.create('div')
        :attr('data-checklist', checklistId) -- Use the provided checklist identifier
        :addClass('icon-list-container icon-list-checklist')
    local list = mw.html.create('div') -- Use 'div' for block-level stacking

    for _, itemString in ipairs(itemStrings) do
        local itemData = mw.text.split(itemString, '>')
        local itemName = itemData[2]:match('title="([^"]+)"')

        local listItem = mw.html.create('div') -- Use 'div' for stacking
            :attr('data-item', itemName)
            :addClass('custom-icon')
            :wikitext(itemString)

        list:node(listItem)
    end

    container:node(list)
    if useColumns then
        return tostring(p.createColumns({container}, useColumns))
    else
        return tostring(container)
    end
end

function p.displayInline(itemStrings)
	local container = mw.html.create('span')
    container:addClass('icon-list-inline')
	for _, itemString in ipairs(itemStrings) do
		container:wikitext(itemString .. ' ')
	end
	return tostring(container)
end

function p.displayInlineAnd(itemStrings)
	local container = mw.html.create('span')
    container:addClass('icon-list-inline-and')
	for i, itemString in ipairs(itemStrings) do
		if i == #itemStrings then
			container:wikitext('and ' .. itemString)
		else
			container:wikitext(itemString .. ', ')
		end
	end
	return tostring(container)
end

function p.displayInlineOr(itemStrings)
	local container = mw.html.create('span')
    container:addClass('icon-list-inline-or')
	for i, itemString in ipairs(itemStrings) do
		if i == #itemStrings then
			container:wikitext('or ' .. itemString)
		else
			container:wikitext(itemString .. ', ')
		end
	end
	return tostring(container)
end

return p