Module:STARDIT validator

From STARDIT
Jump to navigation Jump to search

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

--[[
Module:STARDIT validator

Helpers for Template:Validator parameter (sandbox for now).

  checklist - shows the fixed list of report sections with a ticked or empty
              box for each, from the comma-separated list the form saves.
              {{#invoke:STARDIT validator|checklist|checked=Aims, Contributors}}

  stale     - if the report has been edited after the date of a check, says so.
              {{#invoke:STARDIT validator|stale|date=2026-10-27}}

Design rules:
  * Fails open: a section name that is not on the fixed list is still shown
    (as "Also recorded"), never silently dropped.
  * Never claims more than was recorded: no list means no checklist is shown.
]]

local p = {}

-- The fixed list validators tick against. If this list changes, the form's
-- values= list for val_sections must change to match, character for character.
p.SECTIONS = {
	'Summary and description',
	'Aims',
	'Keywords',
	'Contributors',
	'Inputs and funding',
	'Ethics',
	'Outputs',
	'Report authorship',
	'Sources',
}

local TICKED = '\226\152\145'   -- U+2611 ballot box with check
local EMPTY = '\226\152\144'    -- U+2610 ballot box

local function clean(s)
	if s == nil then return nil end
	s = mw.text.trim(tostring(s))
	if s == '' then return nil end
	return s
end

function p.checklist(frame)
	local raw = clean(frame.args.checked)
	if not raw then
		return ''
	end
	local ticked, order = {}, {}
	for _, v in ipairs(mw.text.split(raw, ',', true)) do
		v = clean(v)
		if v then
			local key = mw.ustring.lower(v)
			if not ticked[key] then
				ticked[key] = v
				table.insert(order, key)
			end
		end
	end
	local known = {}
	local items = {}
	for _, s in ipairs(p.SECTIONS) do
		local key = mw.ustring.lower(s)
		known[key] = true
		local mark = ticked[key] and TICKED or EMPTY
		local state = ticked[key] and 'checked' or 'not checked'
		table.insert(items, '<span title="' .. state .. '" style="white-space:nowrap;margin-right:0.8em;">'
			.. mark .. '&nbsp;' .. s .. '</span>')
	end
	local extra = {}
	for _, key in ipairs(order) do
		if not known[key] then
			table.insert(extra, mw.text.nowiki(ticked[key]))
		end
	end
	local out = table.concat(items, ' ')
	if #extra > 0 then
		out = out .. '<br>Also recorded: ' .. table.concat(extra, '; ')
	end
	return out
end

-- Accepts YYYY-MM-DD or YYYY/MM/DD (what the date picker saves).
local function dateNumber(s)
	if not s then return nil end
	local y, m, d = s:match('^(%d%d%d%d)[%-/](%d%d?)[%-/](%d%d?)')
	if not y then return nil end
	return tonumber(y) * 10000 + tonumber(m) * 100 + tonumber(d)
end

function p.stale(frame)
	local checked = dateNumber(clean(frame.args.date))
	if not checked then
		return ''
	end
	local ts = clean(frame:preprocess('{{REVISIONTIMESTAMP}}'))
	if not ts or not ts:match('^%d%d%d%d%d%d%d%d') then
		return ''
	end
	if tonumber(ts:sub(1, 8)) > checked then
		return "''(the report has been edited since this check; last edited "
			.. ts:sub(1, 4) .. '-' .. ts:sub(5, 6) .. '-' .. ts:sub(7, 8) .. ")''"
	end
	return ''
end

return p