Module:Sandbox/User:Wolaznik/Uses tool list
Module documentation
This documentation is transcluded from Template:Module sandbox/doc. [edit] [history] [purge]
Module:Sandbox/User:Wolaznik/Uses tool list requires Module:Addcommas.
Module:Sandbox/User:Wolaznik/Uses tool list requires Module:SCP.
Module:Sandbox/User:Wolaznik/Uses tool list requires Module:Yesno.
This module is a sandbox for Wolaznik. It can be used to test changes to existing modules, prototype new modules, or just experimenting with lua features.
Invocations of this sandbox should be kept in userspace; if the module is intended for use in other namespaces, it should be moved out of the sandbox into a normal module and template.
This default documentation can be overridden by creating the /doc subpage of this module, as normal.
local p = {}
local commas = require('Module:Addcommas')
local skillPic = require('Module:SCP')._main
local yesNo = require('Module:Yesno')
local lang = mw.getContentLanguage()
local trim = mw.text.trim
local split = mw.text.split
local jsonDecode = mw.text.jsonDecode
function buildRow(recipe, tool)
local ret = mw.html.create('tr')
-- Outputs
ret:tag('td'):wikitext(recipe.output.image)
ret:tag('td'):attr('data-sort-value', recipe.output.name):wikitext(commas._add(recipe.output.quantity) .. ' × [[' .. recipe.output.name .. ']]' .. (recipe.output.subtxt ~= nil and '<br/><small>(' .. recipe.output.subtxt .. ')</small>' or ''))
-- Members
if(yesNo(recipe.members)) then
ret:tag('td'):wikitext("[[File:Member icon.png|center|link=Members|alt=Members]]")
elseif(not yesNo(recipe.members)) then
ret:tag('td'):wikitext("[[File:Free-to-play icon.png|center|link=Free-to-play|alt=Free-to-play]]")
end
--Tools
local toolList = mw.html.create('ul'):addClass('products-materials')
local toolSortValue = nil
local tools = split(recipe.tools, ",")
for i, toolV in ipairs(tools) do
toolList:tag('li'):attr('data-sort-value', i == 1 and tooV or ''):wikitext(toolV) -- For highlighting _all_ tools --- :addClass('production-selected')
end
ret:tag('td'):addClass('plainlist'):node(toolList)
-- Skills (level)
-- Skills (xp)
local skillList = mw.html.create('ul'):addClass('skills-list')
local xpList = mw.html.create('ul'):addClass('skills-list')
if(#recipe.skills == 0) then
skillList:tag('li'):wikitext('None')
xpList:tag('li'):wikitext('None')
ret:tag('td'):addClass('table-na plainlist'):node(skillList)
ret:tag('td'):addClass('table-na plainlist'):node(xpList)
else
for i, skill in ipairs(recipe.skills) do
skillList:tag('li'):attr('data-sort-value', i == 1 and skill.level or ''):wikitext(skillPic(lang:ucfirst(skill.name), skill.level))
xpList:tag('li'):attr('data-sort-value', i == 1 and skill.experience or ''):wikitext(commas._strip(skill.experience) ~= nil and skillPic(lang:ucfirst(skill.name), skill.experience) or skill.experience)
end
ret:tag('td'):addClass('plainlist'):node(skillList)
ret:tag('td'):addClass('plainlist'):node(xpList)
end
-- Inputs
local matList = mw.html.create('ul')
local materialSortValue = nil
for _, mat in ipairs(recipe.materials) do
local quantity = string.gsub(mat.quantity, '%-', '–')
if(materialSortValue == nil) then
materialSortValue = quantity
end
matList:tag('li'):wikitext(string.format('%s × [[%s]]', commas._add(quantity), mat.name))
end
ret:tag('td'):addClass('plainlist'):attr('data-sort-value', materialSortValue):node(matList)
return ret
end
function createHeader()
local header = mw.html.create('table'):addClass('wikitable sortable products-list align-center-1 align-left-2 align-center-3'):done()
header:tag('tr'):tag('th'):attr('colspan', '2'):wikitext('Product'):done()
:tag('th'):wikitext('Members'):done()
:tag('th'):wikitext('Tool'):done()
:tag('th'):attr('data-sort-type', 'number'):wikitext('Skills'):done()
:tag('th'):attr('data-sort-type', 'number'):wikitext('XP'):done()
:tag('th'):wikitext('Materials'):done()
return header
end
-- If both variables contain the same element as part of a list (or single string)
function bothContain(argOne, argTwo)
if(argOne == nil) or (argOne == '') or (argTwo == nil) or (argTwo == '') then
return false
elseif((type(argOne) == 'string') and (string.find(argOne, ',') == nil)) and ((type(argTwo) == 'string') and (string.find(argTwo, ',') == nil)) then
return trim(argOne) == trim(argTwo)
else
if(type(argOne) == 'string') then
argOne = split(argOne, "%s*,%s*")
end
if(type(argTwo) == 'string') then
argTwo = split(argTwo, "%s*,%s*")
end
for i, v in ipairs(argOne) do
for j, w in ipairs(argTwo) do
if(trim(w) == trim(v)) then
return true
end
end
end
return false
end
end
function p.loadData(tools, limit, offset)
local query = {
'[[Uses tool::'.. table.concat(tools, '||') ..']]',
'[[Production JSON::+]]',
'?=#-',
'?Production JSON = json',
limit = limit or 500,
offset = offset or 0,
}
local t1 = os.clock()
local smwData = mw.smw.ask(query)
local t2 = os.clock()
if(smwData == nil) then
return nil
end
mw.log(string.format('SMW: entries %d, time elapsed: %.3f ms.', #smwData, (t2 - t1) * 1000))
data = {}
for i, v in ipairs(smwData) do
if type(v['json']) == 'string' then
table.insert(data, jsonDecode(v['json']))
elseif type(v['json']) == 'table' then
for _, w in ipairs(v['json']) do
table.insert(data, jsonDecode(w))
end
end
end
-- Remove recipes that do not use at least one of the input tools
-- Iterate in reverse so pops do not interrupt iteration
for i = #data, 1, -1 do
if(not bothContain(tools, data[i].tools)) then
table.remove(data, i)
end
end
-- Sort table values by order of tool input
if((#tools == 1)) then -- or (#data == 1)
return data
else
local ret = {}
-- This tracks the current position of where inserts should occur
local toolCountOffset = {}
for i = 1, #tools, 1 do
table.insert(toolCountOffset, 0)
end
for i, recipe in ipairs(data) do
local pos = 0
for j, tool in ipairs(tools) do
pos = pos + toolCountOffset[j]
if(bothContain(recipe.tools, tool)) then
table.insert(ret, pos + 1, recipe)
toolCountOffset[j] = toolCountOffset[j] + 1
break
end
end
end
return ret
end
end
function p._main(args)
local tool = args ~= nil and args[1] or mw.title.getCurrentTitle().text
local tools = {}
if(string.find(tool, ',') == nil) then
table.insert(tools, trim(tool))
else
for _, toolV in ipairs(split(tool, ",")) do
table.insert(tools, trim(toolV))
end
end
data = p.loadData(tools, args.limit, args.offset)
if(data == nil) then
return 'Failed to find products using that tool - ensure it is spelled correctly. (ERR: no results from SMW)[[Category:Empty drop lists]]'
end
local ret = createHeader()
for _, recipe in ipairs(data) do
ret:node(buildRow(recipe, tools))
end
return tostring(ret)
end
--[[ DEBUG
= p._main({'Hammer'})
= p._main({'Hammer, Pickaxe'})
--]]
function p.main(frame)
--mw.logObject(frame)
local args = frame:getParent().args
return p._main(args)
end
return p