Last edited 4 months ago
by Meryam Sahin

Module:NeoWikiRollup: Difference between revisions

Meryam Sahin (talk | contribs)
No edit summary
Meryam Sahin (talk | contribs)
No edit summary
 
Line 87: Line 87:
  end
  end


  local out = { '{| class="wikitable"', '! ' .. table.concat(columns, ' !! ') }
  local out = { '{| class="table table-striped"', '! ' .. table.concat(columns, ' !! ') }


  for _, row in ipairs(rows) do
  for _, row in ipairs(rows) do

Latest revision as of 11:20, 18 June 2026

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

local p = {}

local nw = require('mw.neowiki')

function p.value(frame)
 local property = frame.args[1]
 local page = frame.args['page']

 local options = nil
 if page then options = { page = page } end

 local v = nw.getValue(property, options)
 return tostring(v or '')
end

function p.values(frame)
 local property = frame.args[1]
 local page = frame.args['page']
 local separator = frame.args['separator'] or ', '

 local options = nil
 if page then options = { page = page } end

 local all = nw.getAll(property, options)
 if not all then return '' end

 local parts = {}
 for _, item in ipairs(all) do
  parts[#parts + 1] = tostring(item)
 end

 return table.concat(parts, separator)
end

function p.subject(frame)
 local page = frame.args[1]
 local s = nw.getMainSubject(page)
 if not s then return 'No subject found' end

 local rows = {}
 rows[#rows + 1] = '{| class="table table-striped"'
 rows[#rows + 1] = '! Property !! Type !! Value(s)'

 for name, stmt in pairs(s.statements) do
  local vals = {}
  for _, v in ipairs(stmt.values) do
   if type(v) == 'table' then
    vals[#vals + 1] = v.label or v.target or tostring(v)
   else
    vals[#vals + 1] = tostring(v)
   end
  end
  rows[#rows + 1] = '|-'
  rows[#rows + 1] = '| ' .. name .. ' || ' .. stmt.type .. ' || ' .. table.concat(vals, ', ')
 end

 rows[#rows + 1] = '|}'
 return table.concat(rows, '\n')
end

function p.children(frame)
 local page = frame.args[1]
 local children = nw.getChildSubjects(page)

 if not children or #children == 0 then return 'No child subjects' end

 local parts = {}
 for _, child in ipairs(children) do
  parts[#parts + 1] = "'''" .. child.label .. "''' (" .. child.schema .. ")"
 end

 return table.concat(parts, ', ')
end

local function renderRowsAsTable(rows, columns, linkColumns, linkNamespace, labelMode)
 if #rows == 0 then return 'No results' end

 if not columns then
  columns = {}
  for k in pairs(rows[1]) do columns[#columns + 1] = k end
  table.sort(columns)
 end

 local linkSet = {}
 if linkColumns then
  for _, col in ipairs(linkColumns) do linkSet[col] = true end
 end

 local out = { '{| class="table table-striped"', '! ' .. table.concat(columns, ' !! ') }

 for _, row in ipairs(rows) do
  local cells = {}

  for _, col in ipairs(columns) do
   local v = row[col]
   local cell = v == nil and '' or tostring(v)

   if linkSet[col] and cell ~= '' then
    local ns = linkNamespace and linkNamespace[col]

    local fullTitle
    if ns and ns ~= '' then
     fullTitle = ns .. ':' .. cell
    else
     fullTitle = cell
    end

    local titleObj = mw.title.new(fullTitle)

    local label
    if labelMode == 'full' then
     label = titleObj and titleObj.text or cell
    else
     label = (titleObj and titleObj.subpageText ~= '') and titleObj.subpageText or (titleObj and titleObj.text or cell)
    end

    cell = '[[' .. fullTitle .. '|' .. label .. ']]'
   end

   cells[#cells + 1] = cell
  end

  out[#out + 1] = '|-'
  out[#out + 1] = '| ' .. table.concat(cells, ' || ')
 end

 out[#out + 1] = '|}'
 return table.concat(out, '\n')
end

function p.query(frame)

 local columns = nil
 if frame.args.columns then
  columns = mw.text.split(frame.args.columns, ',%s*')
 end

 local linkColumns = nil
 if frame.args.linkColumns then
  linkColumns = mw.text.split(frame.args.linkColumns, ',%s*')
 end

 local linkNamespace = {}
 for k, v in pairs(frame.args) do
  if type(k) == 'string' then
   local col = k:match('^linkNamespace(.+)$')
   if col then
    linkNamespace[mw.text.trim(col)] = mw.text.trim(v)
   end
  end
 end

 local labelMode = frame.args.linkLabel or 'subpage'

 return renderRowsAsTable(
  nw.query(frame.args[1]),
  columns,
  linkColumns,
  linkNamespace,
  labelMode
 )
end

local function statementValue(stmt)
 if not stmt or not stmt.values or stmt.values[1] == nil then return nil end
 local v = stmt.values[1]
 if type(v) == 'table' then return v.label or v.target end
 return v
end

function p.childTable(frame)
 local columns = mw.text.split(frame.args.columns or '', ',%s*')
 local schemaFilter = frame.args.schema
 local sortBy = frame.args.sortBy
 local sortDir = frame.args.sortDir or 'desc'

 local numberSet = {}
 if frame.args.numberColumns then
  for _, col in ipairs(mw.text.split(frame.args.numberColumns, ',%s*')) do
   numberSet[col] = true
  end
 end

 local children = nw.getChildSubjects()
 if not children then return '' end

 local lang = mw.getContentLanguage()
 local rows = {}

 for _, child in ipairs(children) do
  if not schemaFilter or child.schema == schemaFilter then
   local row = {}
   for _, col in ipairs(columns) do
    local v = statementValue(child.statements[col])
    if v == nil then
     row[col] = ''
    elseif numberSet[col] and tonumber(v) then
     row[col] = lang:formatNum(tonumber(v))
    else
     row[col] = tostring(v)
    end
   end
   if sortBy then
    row.__sortValue = statementValue(child.statements[sortBy])
   end
   rows[#rows + 1] = row
  end
 end

 if sortBy then
  table.sort(rows, function(a,b)
   local av,bv = a.__sortValue, b.__sortValue
   local an,bn = tonumber(av), tonumber(bv)
   if an and bn then
    if sortDir == 'asc' then return an < bn end
    return an > bn
   end
   if sortDir == 'asc' then return tostring(av) < tostring(bv) end
   return tostring(av) > tostring(bv)
  end)
 end

 return renderRowsAsTable(rows, columns, nil)
end

function p.productsFoundedSince(frame)
 local year = tonumber(frame.args[1]) or 2000
 return renderRowsAsTable(nw.query(
  'MATCH (n:Product) WHERE n.`Available since` >= $year RETURN n.name AS name, n.`Available since` AS year ORDER BY year',
  { year = year }
 ))
end

local function propertyDetails(prop)
 local details = {}

 if prop.type == 'select' then
  local labels = {}
  for _, option in ipairs(prop.options) do
   labels[#labels + 1] = option.label
  end
  details[#details + 1] = 'options: ' .. table.concat(labels, ', ')
 elseif prop.type == 'number' then
  if prop.minimum ~= nil then details[#details + 1] = 'min: ' .. tostring(prop.minimum) end
  if prop.maximum ~= nil then details[#details + 1] = 'max: ' .. tostring(prop.maximum) end
  if prop.precision ~= nil then details[#details + 1] = 'precision: ' .. tostring(prop.precision) end
 elseif prop.type == 'relation' then
  details[#details + 1] = 'targetSchema: ' .. prop.targetSchema
  details[#details + 1] = 'relation: ' .. prop.relation
 elseif prop.type == 'text' or prop.type == 'url' then
  if prop.multiple then details[#details + 1] = 'multiple: true' end
  if prop.uniqueItems then details[#details + 1] = 'uniqueItems: true' end
 end

 return table.concat(details, ', ')
end

function p.schema(frame)
 local schema = nw.getSchema(frame.args[1])
 if not schema then return 'Schema not found' end

 local rows = {}
 for _, prop in ipairs(schema.properties) do
  rows[#rows + 1] = {
   Name = prop.name,
   Type = prop.type,
   Required = prop.required and 'Yes' or 'No',
   Details = propertyDetails(prop)
  }
 end

 return renderRowsAsTable(rows, { 'Name', 'Type', 'Required', 'Details' })
end

return p