Line 1: |
Line 1: |
| local p = {} | | local p = {} |
| local private = {} | | local private = {} |
− |
| |
− | --##########
| |
− | --## Constants
| |
− | --##########
| |
− | -- The valid status values.
| |
− | local statuses = {
| |
− | ok = "ok",
| |
− | optional = "optional",
| |
− | unofficial = "unofficial",
| |
− | workaround = "workaround",
| |
− | broken = "broken",
| |
− | abandoned = "abandoned",
| |
− | obsolete = "obsolete"
| |
− | }
| |
− |
| |
| | | |
| --########## | | --########## |
Line 23: |
Line 8: |
| -- @test mw.log(p.header()) | | -- @test mw.log(p.header()) |
| function p.header() | | function p.header() |
− | local row = mw.html.create("tr") | + | return |
− | row:node(mw.html.create("th"):wikitext("mod name"))
| + | '<table class="wikitable plainlinks">' |
− | row:node(mw.html.create("th"):wikitext("author"))
| + | .. "<tr><th>mod name</th><th>author</th><th>compatibility</th><th>broke in</th><th>source</th><th> </th></tr>"; |
− | row:node(mw.html.create("th"):wikitext("compatibility"))
| |
− | row:node(mw.html.create("th"):wikitext("broke in"))
| |
− | row:node(mw.html.create("th"):wikitext("source"))
| |
− | row:node(mw.html.create("th"):wikitext(" "))
| |
− | | |
− | return '<table class="wikitable plainlinks">' .. tostring(row)
| |
| end | | end |
| | | |
Line 45: |
Line 24: |
| function p.entry(frame) | | function p.entry(frame) |
| -- read input args | | -- read input args |
− | local names = private.parseCommaDelimited((private.trim(frame.args["name"]) or '') .. ',' .. (private.trim(frame.args["name2"]) or '')) | + | local names = private.parseCommaDelimited((frame.args["name"] or '') .. ',' .. (frame.args["name2"] or '')) |
− | local authors = private.parseCommaDelimited((private.trim(frame.args["author"]) or '') .. ',' .. (private.trim(frame.args["author2"]) or '')) | + | local authors = private.parseCommaDelimited((frame.args["author"] or '') .. ',' .. (frame.args["author2"] or '')) |
− | local ids = private.parseCommaDelimited((private.trim(frame.args["id"]) or '') .. ',' .. (private.trim(frame.args["old ids"]) or '')) | + | local ids = private.parseCommaDelimited((frame.args["id"] or '') .. ',' .. (frame.args["old ids"] or '')) |
− | local nexusID = private.emptyToNil(private.trim(frame.args["nexus id"])) | + | local nexusID = private.emptyToNil(frame.args["nexus id"]) |
− | local github = private.emptyToNil(private.trim(frame.args["github"])) | + | local github = private.emptyToNil(frame.args["github"]) |
− | local summary = private.emptyToNil(private.trim(frame.args["summary"])) | + | local summary = private.emptyToNil(frame.args["summary"]) |
− | local brokeIn = private.emptyToNil(private.trim(frame.args["broke in"])) | + | local brokeIn = private.emptyToNil(frame.args["broke in"]) |
| | | |
− | local status = private.emptyToNil(private.trim(frame.args["status"])) | + | local status = private.emptyToNil(frame.args["status"]) |
− | local unofficialVersion = private.emptyToNil(private.trim(frame.args["unofficial version"])) | + | local unofficialVersion = private.emptyToNil(frame.args["unofficial version"]) |
− | local unofficialUrl = private.emptyToNil(private.trim(frame.args["unofficial url"])) | + | local unofficialUrl = private.emptyToNil(frame.args["unofficial url"]) |
− | local oldIDs = private.emptyToNil(private.trim(frame.args["old ids"])) | + | local oldIDs = private.emptyToNil(frame.args["old ids"]) |
− | local chucklefishID = private.emptyToNil(private.trim(frame.args["cf id"])) | + | local chucklefishID = private.emptyToNil(frame.args["cf id"]) |
− | local customUrl = private.emptyToNil(private.trim(frame.args["url"])) | + | local customUrl = private.emptyToNil(frame.args["url"]) |
− | local customSource = private.emptyToNil(private.trim(frame.args["source"])) | + | local customSource = private.emptyToNil(frame.args["source"]) |
− | local name2 = private.emptyToNil(private.trim(frame.args["name2"])) | + | local name2 = private.emptyToNil(frame.args["name2"]) |
− | local author2 = private.emptyToNil(private.trim(frame.args["author2"])) | + | local author2 = private.emptyToNil(frame.args["author2"]) |
| local links = private.parseCommaDelimited(frame.args["links"]) | | local links = private.parseCommaDelimited(frame.args["links"]) |
| local warnings = private.parseCommaDelimited(frame.args["warnings"]) | | local warnings = private.parseCommaDelimited(frame.args["warnings"]) |
| | | |
− | local betaSummary = private.emptyToNil(private.trim(frame.args["beta summary"])) | + | local betaSummary = private.emptyToNil(frame.args["beta summary"]) |
− | local betaBrokeIn = private.emptyToNil(private.trim(frame.args["beta broke in"])) | + | local betaBrokeIn = private.emptyToNil(frame.args["beta broke in"]) |
− | local betaStatus = private.emptyToNil(private.trim(frame.args["beta status"])) | + | local betaStatus = private.emptyToNil(frame.args["beta status"]) |
− | local betaUnofficialVersion = private.emptyToNil(private.trim(frame.args["beta unofficial version"])) | + | local betaUnofficialVersion = private.emptyToNil(frame.args["beta unofficial version"]) |
− | local betaUnofficialUrl = private.emptyToNil(private.trim(frame.args["beta unofficial url"])) | + | local betaUnofficialUrl = private.emptyToNil(frame.args["beta unofficial url"]) |
| | | |
| -- parse compatibility | | -- parse compatibility |
Line 96: |
Line 75: |
| -- get background color | | -- get background color |
| local background = '#999' | | local background = '#999' |
− | if compat.status == statuses.ok or compat.status == statuses.optional then | + | if compat.status == "ok" or compat.status == "optional" then |
| background = '#9F9' | | background = '#9F9' |
− | elseif compat.status == statuses.workaround or compat.status == statuses.unofficial then | + | elseif compat.status == "workaround" or compat.status == "unofficial" then |
| background = '#CF9' | | background = '#CF9' |
− | elseif compat.status == statuses.broken then | + | elseif compat.status == "broken" then |
| background = '#F99' | | background = '#F99' |
− | elseif compat.status == statuses.obsolete or compat.status == statuses.abandoned then | + | elseif compat.status == "obsolete" or compat.status == "abandoned" then |
| background = '#999' | | background = '#999' |
| end | | end |
Line 109: |
Line 88: |
| local row = mw.html.create("tr") | | local row = mw.html.create("tr") |
| row:addClass("mod") | | row:addClass("mod") |
− | row:attr("id", names[1] and mw.uri.anchorEncode(names[1]) or nil); | + | row:attr("id", names[1] and mw.uri.anchorEncode(names[1])); |
| row:attr("data-name", table.concat(names, ",")) | | row:attr("data-name", table.concat(names, ",")) |
| row:attr("data-id", table.concat(ids, ",")) | | row:attr("data-id", table.concat(ids, ",")) |
Line 123: |
Line 102: |
| row:attr("data-unofficial-version", compat.unofficialVersion) | | row:attr("data-unofficial-version", compat.unofficialVersion) |
| row:attr("data-unofficial-url", compat.unofficialUrl) | | row:attr("data-unofficial-url", compat.unofficialUrl) |
− | row:attr("data-beta-status", betaCompat and betaCompat.status or nil) | + | row:attr("data-beta-status", betaCompat and betaCompat.status) |
− | row:attr("data-beta-summary", betaCompat and betaCompat.summary or nil) | + | row:attr("data-beta-summary", betaCompat and betaCompat.summary) |
− | row:attr("data-beta-broke-in", betaCompat and betaCompat.brokeIn or nil) | + | row:attr("data-beta-broke-in", betaCompat and betaCompat.brokeIn) |
− | row:attr("data-beta-unofficial-version", betaCompat and betaCompat.unofficialVersion or nil) | + | row:attr("data-beta-unofficial-version", betaCompat and betaCompat.unofficialVersion) |
− | row:attr("data-beta-unofficial-url", betaCompat and betaCompat.unofficialUrl or nil) | + | row:attr("data-beta-unofficial-url", betaCompat and betaCompat.unofficialUrl) |
| row:attr("data-warnings", private.emptyToNil(table.concat(warnings, ","))) | | row:attr("data-warnings", private.emptyToNil(table.concat(warnings, ","))) |
| row:attr("style", "line-height: 1em; background: " .. background .. ";") | | row:attr("style", "line-height: 1em; background: " .. background .. ";") |
Line 135: |
Line 114: |
| do | | do |
| local field = mw.html.create("td") | | local field = mw.html.create("td") |
| + | |
| field:wikitext("[" .. (url or '') .. " " .. (names[1] or '') .. "]") | | field:wikitext("[" .. (url or '') .. " " .. (names[1] or '') .. "]") |
| | | |
− | if #names > 1 then | + | local nameCount = #names |
− | local altNames = mw.html.create("small"):wikitext("(aka ") | + | if nameCount > 1 then |
− | for k, v in pairs(names) do | + | field:wikitext("<br /><small>(aka ") |
− | if k > 1 then | + | for i = 1, nameCount do |
− | altNames:wikitext(v) | + | if i > 1 then |
| + | field:wikitext(names[i]) |
| + | if i < nameCount then |
| + | field:wikitext(", ") |
| + | end |
| end | | end |
| end | | end |
− | altNames:wikitext(")") | + | field:wikitext(")</small>") |
− | field:node(mw.html.create("br"))
| |
− | field:node(altNames)
| |
| end | | end |
| | | |
Line 158: |
Line 140: |
| | | |
| field:wikitext(authors[1]) | | field:wikitext(authors[1]) |
− | if #authors > 1 then | + | |
− | local altNames = mw.html.create("small"):wikitext("(aka ") | + | local authorCount = #authors |
− | for k, v in pairs(authors) do | + | if authorCount > 1 then |
− | if k > 1 then | + | field:wikitext("<br /><small>(aka ") |
− | altNames:wikitext(v) | + | for i = 1, authorCount do |
| + | if i > 1 then |
| + | field:wikitext(authors[i]) |
| + | if i < authorCount then |
| + | field:wikitext(", ") |
| + | end |
| end | | end |
| end | | end |
− | altNames:wikitext(")") | + | field:wikitext(")</small>") |
− | field:node(mw.html.create("br"))
| |
− | field:node(altNames)
| |
| end | | end |
| | | |
Line 180: |
Line 165: |
| -- stable status | | -- stable status |
| field:wikitext(compat.summaryIcon .. " " .. compat.summary) | | field:wikitext(compat.summaryIcon .. " " .. compat.summary) |
− | if compat.status == statuses.optional then | + | if compat.status == "optional" then |
| field:wikitext("<ref name=\"optional-update\" />") | | field:wikitext("<ref name=\"optional-update\" />") |
| end | | end |
Line 186: |
Line 171: |
| -- beta status | | -- beta status |
| if betaCompat ~= nill then | | if betaCompat ~= nill then |
− | field:node(mw.html.create("br")) | + | field:wikitext("<br />") |
| field:wikitext("'''SDV beta only:''' " .. betaCompat.summaryIcon .. " " .. betaCompat.summary) | | field:wikitext("'''SDV beta only:''' " .. betaCompat.summaryIcon .. " " .. betaCompat.summary) |
− | if betaCompat.status == statuses.optional then | + | if betaCompat.status == "optional" then |
| field:wikitext("<ref name=\"optional-update\" />") | | field:wikitext("<ref name=\"optional-update\" />") |
| end | | end |
Line 194: |
Line 179: |
| | | |
| -- warnings | | -- warnings |
− | if #warnings > 0 then | + | do |
− | for k, v in pairs(warnings) do
| + | local warningCount = #warnings |
− | field:node(mw.html.create("br"))
| + | if warningCount > 0 then |
− | field:wikitext("⚠ " .. v)
| + | for i = 1, warningCount do |
| + | field:wikitext("<br />⚠ " .. warnings[i]) |
| + | end |
| end | | end |
| end | | end |
Line 221: |
Line 208: |
| -- add 'source' field | | -- add 'source' field |
| do | | do |
− | local field = mw.html.create("td")
| |
− |
| |
| if sourceUrl then | | if sourceUrl then |
− | field:wikitext("[" .. sourceUrl .. " source]") | + | row:wikitext("<td>[" .. sourceUrl .. " source]</td>") |
| else | | else |
− | field:wikitext("<span style=\"color: red; font-size: 0.85em; opacity: 0.5;\">closed source</span>") | + | row:wikitext("<td><span style=\"color: red; font-size: 0.85em; opacity: 0.5;\">closed source</span></td>") |
| end | | end |
− |
| |
− | row:node(field)
| |
| row:newline() | | row:newline() |
| end | | end |
Line 242: |
Line 225: |
| | | |
| -- reference links | | -- reference links |
− | for k, v in pairs(links) do | + | do |
− | field:wikitext("[" .. v .. " " .. k .. "] ")
| + | local linkCount = #links |
| + | for i = 1, linkCount do |
| + | field:wikitext("[" .. links[i] .. " " .. i .. "] ") |
| + | end |
| end | | end |
| | | |
Line 252: |
Line 238: |
| | | |
| -- backwards-compatible metadata (temporary) | | -- backwards-compatible metadata (temporary) |
− | local metadata = mw.html.create("div") | + | field:wikitext('<div div class="mod-metadata" style="display: none;">') |
− | metadata:addClass("mod-metadata")
| + | field:wikitext('<div class="mod-anchor">' .. (names[1] and mw.uri.anchorEncode(names[1])) .. "</div>") |
− | metadata:attr("style", "display: none;")
| + | field:wikitext('<div class="mod-id">' .. mw.text.encode(table.concat(ids, ",")) .. "</div>") |
− | metadata:node(mw.html.create("div"):addClass("mod-anchor"):wikitext(names[1] and mw.uri.anchorEncode(names[1]))) | + | field:wikitext('<div class="mod-url">' .. mw.text.encode(url) .. "</div>") |
− | metadata:node(mw.html.create("div"):addClass("mod-id"):wikitext(table.concat(ids, ",")))
| |
− | metadata:node(mw.html.create("div"):addClass("mod-url"):wikitext(url))
| |
| if nexusID ~= nil then | | if nexusID ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-nexus-id"):wikitext(nexusID)) | + | field:wikitext('<div class="mod-nexus-id">' .. mw.text.encode(nexusID) .. "</div>") |
| end | | end |
| if chucklefishID ~= nil then | | if chucklefishID ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-cf-id"):wikitext(chucklefishID)) | + | field:wikitext('<div class="mod-cf-id">' .. mw.text.encode(chucklefishID) .. "</div>") |
| end | | end |
| if github ~= nil then | | if github ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-github"):wikitext(github)) | + | field:wikitext('<div class="mod-github">' .. mw.text.encode(github) .. '</div>') |
| end | | end |
| if customSource ~= nil then | | if customSource ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-custom-source"):wikitext(customSource)) | + | field:wikitext('<div class="mod-custom-source">' .. mw.text.encode(customSource) .. '</div>') |
| end | | end |
− | metadata:node(mw.html.create("div"):addClass("mod-status"):wikitext(compat.status)) | + | field:wikitext('<div class="mod-status">' .. mw.text.encode(compat.status) .. '</div>') |
| if compat.brokeIn ~= nil then | | if compat.brokeIn ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-broke-in"):wikitext(compat.brokeIn)) | + | field:wikitext('<div class="mod-broke-in">' .. mw.text.encode(compat.brokeIn) .. '</div>') |
| end | | end |
| if compat.unofficialVersion ~= nil and compat.unofficialUrl ~= nil then | | if compat.unofficialVersion ~= nil and compat.unofficialUrl ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-unofficial-version"):wikitext(compat.unofficialVersion)) | + | field:wikitext('<div class="mod-unofficial-version">' .. mw.text.encode(compat.unofficialVersion) .. '</div>') |
− | metadata:node(mw.html.create("div"):addClass("mod-unofficial-url"):wikitext(compat.unofficialUrl)) | + | field:wikitext('<div class="mod-unofficial-url">' .. mw.text.encode(compat.unofficialUrl) .. '</div>') |
| end | | end |
| if betaCompat ~= nil then | | if betaCompat ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-beta-status"):wikitext(betaCompat.status)) | + | field:wikitext('<div class="mod-beta-status">' .. mw.text.encode(betaCompat.status) .. '</div>') |
| if betaCompat.brokeIn ~= nil then | | if betaCompat.brokeIn ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-beta-broke-in"):wikitext(betaCompat.brokeIn)) | + | field:wikitext('<div class="mod-beta-broke-in">' .. mw.text.encode(betaCompat.brokeIn) .. '</div>') |
| end | | end |
| if betaCompat.unofficialVersion ~= nil and betaCompat.unofficialUrl ~= nil then | | if betaCompat.unofficialVersion ~= nil and betaCompat.unofficialUrl ~= nil then |
− | metadata:node(mw.html.create("div"):addClass("mod-beta-unofficial-version"):wikitext(betaCompat.unofficialVersion)) | + | field:wikitext('<div class="mod-beta-unofficial-version">' .. mw.text.encode(betaCompat.unofficialVersion) .. '</div>') |
− | metadata:node(mw.html.create("div"):addClass("mod-beta-unofficial-url"):wikitext(betaCompat.unofficialUrl)) | + | field:wikitext('<div class="mod-beta-unofficial-url">' .. mw.text.encode(betaCompat.unofficialUrl) .. '</div>') |
| end | | end |
| end | | end |
| if #warnings > 0 then | | if #warnings > 0 then |
− | metadata:node(mw.html.create("div"):addClass("mod-warnings"):wikitext(table.concat(warnings, ","))) | + | field:wikitext('<div class="mod-warnings">' .. mw.text.encode(table.concat(warnings, ",")) .. '</div>') |
| end | | end |
| + | field.wikitext("</div>") |
| | | |
− | field:node(metadata)
| |
| row:node(field) | | row:node(field) |
| end | | end |
Line 308: |
Line 292: |
| if value == nil or value == "" then | | if value == nil or value == "" then |
| return "" | | return "" |
− | else | + | else |
| return key .. "=\"" .. mw.text.encode(value) .. "\"" | | return key .. "=\"" .. mw.text.encode(value) .. "\"" |
| end | | end |
Line 318: |
Line 302: |
| --########## | | --########## |
| -- Get the normalised compatibility info for a mod. | | -- Get the normalised compatibility info for a mod. |
− | -- @param status The specified status code (one of the `statuses` values). If nil or blank, it'll be derived from the other fields. | + | -- @param status The specified status code. If nil or blank, it'll be derived from the other fields. |
| -- @param summary A human-readable summary of the compatibility info. If nil or blank, it'll be derived from the other fields. | | -- @param summary A human-readable summary of the compatibility info. If nil or blank, it'll be derived from the other fields. |
| -- @param brokeIn The SMAPI or Stardew Valley version which broke the mod, if applicable. | | -- @param brokeIn The SMAPI or Stardew Valley version which broke the mod, if applicable. |
Line 325: |
Line 309: |
| -- @param hasSource Whether the mod has public source code available. | | -- @param hasSource Whether the mod has public source code available. |
| function private.getCompatInfo(status, summary, brokeIn, unofficialVersion, unofficialUrl, hasSource) | | function private.getCompatInfo(status, summary, brokeIn, unofficialVersion, unofficialUrl, hasSource) |
− | -- normalise values
| |
− | status = private.emptyToNil(private.trim(status))
| |
− | summary = private.emptyToNil(private.trim(summary))
| |
− | brokeIn = private.emptyToNil(private.trim(brokeIn))
| |
− | unofficialVersion = private.emptyToNil(private.trim(unofficialVersion))
| |
− | unofficialUrl = private.emptyToNil(private.trim(unofficialUrl))
| |
− |
| |
| -- derive status | | -- derive status |
| if status == nil then | | if status == nil then |
| if unofficialVersion ~= nil then | | if unofficialVersion ~= nil then |
− | status = statuses.unofficial | + | status = "unofficial" |
| elseif brokeIn ~= nil then | | elseif brokeIn ~= nil then |
− | status = statuses.broken | + | status = "broken" |
| else | | else |
− | status = statuses.ok | + | status = "ok" |
| end | | end |
| end | | end |
Line 345: |
Line 322: |
| -- derive summary icon | | -- derive summary icon |
| local summaryIcon = "✓" | | local summaryIcon = "✓" |
− | if status == statuses.unofficial or status == statuses.workaround then | + | if status == "unofficial" or status == "workaround" then |
| summaryIcon = "⚠" | | summaryIcon = "⚠" |
− | elseif status == statuses.broken and hasSource then | + | elseif status == "broken" and hasSource then |
| summaryIcon = "↻" | | summaryIcon = "↻" |
− | elseif status == statuses.broken or status == statuses.obsolete or status == statuses.abandoned then | + | elseif status == "broken" or status == "obsolete" or status == "abandoned" then |
| summaryIcon = "✖" | | summaryIcon = "✖" |
| end | | end |
Line 355: |
Line 332: |
| -- derive summary | | -- derive summary |
| if summary == nil then | | if summary == nil then |
− | if status == statuses.ok then | + | if status == "ok" then |
| summary = "use latest version." | | summary = "use latest version." |
− | elseif status == statuses.optional then | + | elseif status == "optional" then |
| summary = "use optional download." | | summary = "use optional download." |
− | elseif status == statuses.unofficial then | + | elseif status == "unofficial" then |
| summary = "broken, use [" .. (unofficialUrl or "") .. " " .. "unofficial version]" | | summary = "broken, use [" .. (unofficialUrl or "") .. " " .. "unofficial version]" |
| if unofficialVersion ~= nil then | | if unofficialVersion ~= nil then |
Line 365: |
Line 342: |
| end | | end |
| summary = summary .. "." | | summary = summary .. "." |
− | elseif status == statuses.workaround then | + | elseif status == "workaround" then |
| summary = "broken. '''error:''' should specify summary." | | summary = "broken. '''error:''' should specify summary." |
− | elseif status == statuses.broken then | + | elseif status == "broken" then |
| if hasSource then | | if hasSource then |
| summary = "broken, not updated yet." | | summary = "broken, not updated yet." |
Line 373: |
Line 350: |
| summary = "broken, not open-source." | | summary = "broken, not open-source." |
| end | | end |
− | elseif status == statuses.obsolete then | + | elseif status == "obsolete" then |
| summary = "obsolete." | | summary = "obsolete." |
− | elseif status == statuses.abandoned then | + | elseif status == "abandoned" then |
| summary = "no longer maintained." | | summary = "no longer maintained." |
| else | | else |
Line 390: |
Line 367: |
| unofficialUrl = unofficialUrl | | unofficialUrl = unofficialUrl |
| } | | } |
− | end
| |
− |
| |
− | -- Trim a string value.
| |
− | -- @param value The string to trim.
| |
− | function private.trim(value)
| |
− | if value ~= nil then
| |
− | return mw.text.trim(value)
| |
− | else
| |
− | return value
| |
− | end
| |
| end | | end |
| | | |
Line 418: |
Line 385: |
| | | |
| if value ~= nil then | | if value ~= nil then |
− | for k, v in pairs(mw.text.split(value, ",", true)) do | + | local values = mw.text.split(value, ",", true) |
− | v = mw.text.trim(v) | + | for i = 1, #values do |
| + | v = mw.text.trim(values[i]) |
| if v ~= "" then | | if v ~= "" then |
| table.insert(result, v) | | table.insert(result, v) |