Module:MaroScale: Difference between revisions

From MTG Wiki
Jump to navigation Jump to search
>Corveroth
No edit summary
>Jerodast
(In my review/learning about this code, was surprised to see <ul> used for the inline list. Realized that format also made the entry align differently than the rest of the row (although that's probably fixable with CSS style). In any case I'll update to use this simpler style. This will make the current lists more compact vertically!)
 
(45 intermediate revisions by one other user not shown)
Line 1: Line 1:
-- Little bit of Lua for building tables for the Storm and Rabiah scales.
-- Little bit of Lua for building tables for the Storm and Rabiah scales.
-- Mechanics have be re-ranked in the past, and it's probably interesting to track their drift.
-- Mechanics have been re-ranked in the past, and it's probably interesting to track their drift.
-- Rather than force editors to track the newest one, let's see if we can't do it in code.
-- Rather than force editors to track the newest one, let's see if we can't do it in code.


local MaroScale = {}
local MaroScale = {}


local sub, match, gsub = mw.ustring.sub, mw.ustring.match, mw.ustring.gsub
local MAX_ENTRIES = 500
-- A list of all sets which have been Standard-legal since the introduction of the Storm Scale (September 2012)
local LEGAL_EXPANSIONS = {
["Return to Ravnica"] = "2012-10-05",
["Gatecrash"] = "2013-02-01",
["Dragon's Maze"] = "2013-05-03",
["Magic 2014"] = "2013-06-13",
["Theros"] = "2013-09-27",
["Born of the Gods"] = "2014-02-07",
["Journey into Nyx"] = "2014-05-02",
["Magic 2015"] = "2014-07-18",
["Khans of Tarkir"] = "2014-09-26",
["Fate Reforged"] = "2015-01-23",
["Dragons of Tarkir"] = "2015-03-17",
["Magic Origins"] = "2015-07-15",
["Battle for Zendikar"] = "2015-10-02",
["Oath of the Gatewatch"] = "2016-01-22",
["Shadows over Innistrad"] = "2016-04-08",
["Eldritch Moon"] = "2016-06-22",
["Kaladesh"] = "2016-09-30",
["Aether Revolt"] = "2016-01-20",
["Amonkhet"] = "2017-04-28",
["Hour of Devastation"] = "2017-07-14",
}
local function generateLink(target, displayText)
if displayText then
return "[["..displayText.."|"..target.."]]"
else
return "[["..target.."]]"
end
end
local function parseRatings(raw)
local outputList = {}
local newestDate, newestRating = 0, 0
local rating, refDate, refString, t
gsub(raw, "{(.-)}", function(a)
rating, refDate, refString = match(a, "(%d+),([%d%-]+),(.+)")
rating = tonumber(rating)
-- Dates MUST be yyyy-mm-dd
t = os.time({year=sub(refDate, 1,4), month=sub(refDate, 6,7), day=sub(refDate, 9,10),})
if t > newestDate then
newestDate = t
newestRating = rating
end
table.insert(outputList, {text = rating..refString, t = t})
end)
return newestRating, outputList
end
local function addPrintings(timeline, printings)
local releaseDate, t
-- Comma-separated list
gsub(printings, "([^,]+)", function(set)
releaseDate = LEGAL_EXPANSIONS[set]
-- The set name provided doesn't match a post-Storm Scale set
if not releaseDate then return end
-- Dates MUST be yyyy-mm-dd
t = os.time({year=sub(releaseDate, 1,4), month=sub(releaseDate, 6,7), day=sub(releaseDate, 9,10),})
table.insert(timeline, {text = generateLink(set), t = t})
end)
return timeline
end
local function sortTimeline(events)
-- Sort all events into chronological order
table.sort(events, function(a,b) return a.t < b.t end)
return events
end
function MaroScale.TableBuilder(frame)
function MaroScale.TableBuilder(frame)
local args = frame:getParent().args -- coming from one layer up
local args = frame:getParent().args -- coming from one layer up
Line 13: Line 94:
     _ = args.type
     _ = args.type
     _ = args.above
     _ = args.above
     for i = 1, 100 do
     for i = 1, MAX_ENTRIES do
        _ = args["name" .. tostring(i)]
         _ = args["entry" .. tostring(i)]
         _ = args["entry" .. tostring(i)]
        _ = args["note" .. tostring(i)]
         _ = args["ratings" .. tostring(i)]
         _ = args["ratings" .. tostring(i)]
        _ = args["printings" .. tostring(i)]
     end
     end
-- Table type
-- Seriously this loop is entirely too clever
local listnums = {}
for k, v in pairs(args) do
local listnum = match('' .. k, '^ratings(%d+)$')
if listnum then table.insert(listnums, {num = tonumber(listnum), alpha = args["entry"..listnum]}) end
end
table.sort(listnums, function(a,b) return a.alpha < b.alpha end)
 
-- Build the table header row
local type = args.type
local type = args.type
local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
local head = tbl:tag("thead"):tag("tr")
tbl:tag("tr")
head:tag("th"):wikitext(type)
:tag("th"):wikitext(type):done()
head:tag("th"):wikitext("Latest ranking")
:tag("th"):wikitext("Latest ranking"):done()
head:tag("th"):wikitext("History of rankings")
:tag("th"):addClass("unsortable"):wikitext("Timeline"):done() -- Last column can't be sorted
 
-- Seriously this loop is entirely too clever
local hasNotes = false
local listnums = {}
for k, v in pairs(args) do
        local listnum = ('' .. k):match('^ratings(%d+)$')
        if listnum then table.insert(listnums, tonumber(listnum)) end
    end
    table.sort(listnums)
-- Reusable loop vars for performance
local name, entry, note, ratings, printings
local linkedEntry, lastRating, timeline
local row, list, cellText
for i, listnum in ipairs(listnums) do
for i, listnum in ipairs(listnums) do
local newestDate, newestRating = 0, 0
listnum = listnum.num
local rating, refDate, refString
-- Retrieve the relevant args for this row
local ratings = {}
name, entry, note, ratings, printings = args["name"..listnum], args["entry"..listnum], args["note"..listnum], args["ratings"..listnum], args["printings"..listnum]
string.gsub(args["ratings"..i], "({.-})", function(a)
rating, refDate, refString = string.match(a, "(%d+),([%d%-]+),(.+)")
-- Create a wikilink for the entry, using name as the target article if provided
rating = tonumber(rating)
linkedEntry = generateLink(entry, name)
table.insert(ratings, {rating = rating, refDate = refDate, refString = refString})
if note then
-- Dates MUST be yyyy-mm-dd
if not hasNotes then hasNotes = true end
local t = os.time({year=string.sub(refDate, 1,4), month=string.sub(refDate, 6,7), day=string.sub(refDate, 9,10),})
linkedEntry = linkedEntry .. frame:expandTemplate({title = "efn", args = { note }})
if t > newestDate then
end
newestDate = t
newestRating = rating
-- Decode the ratings into a table
end
lastRating, timeline = parseRatings(ratings)
end)
-- Add any printings
if printings then
timeline = addPrintings(timeline, printings)
end
-- Sort chronologically
timeline = sortTimeline(timeline)
-- Make the row
row = tbl:tag("tr")
-- First cell
row:tag("td"):wikitext(linkedEntry)
-- maybe later, it's not worth the effort right now
-- Second cell
-- table.sort(ratings, function(a,b) return a.refDate < b.refDate end)
row:tag("td"):wikitext(lastRating)
-- Third cell
--[[ Commented out by jerodast - let's just try regular wikitext.
list = row:tag("td"):tag("ul"):cssText("display:block; margin-top:0; margin-left:0;")
local row = tbl:tag("tr")
for j, event in ipairs(timeline) do
row:tag("td"):wikitext(name or "Name not given")
if j ~= #timeline then
row:tag("td"):wikitext(newestRating or "Rating not found")
list:tag("li"):cssText("display:inline-block;"):wikitext(event.text .. ",&nbsp;")
local list = row:tag("td"):tag("ul")
else
for _, rating in pairs(ratings) do
list:tag("li"):cssText("display:inline-block;"):wikitext(event.text)
list:tag("li"):wikitext(refDate .. rating.refString)
end
end
end
]]
    list = {}
for j, event in ipairs(timeline) do table.insert(list, event.text) end
row:tag("td"):wikitext(table.concat(list,", "))
end
if hasNotes then
return tostring(tbl) .. frame:expandTemplate({title = "notelist"})
else
return tbl
end
end
return tbl
end
end


return MaroScale
return MaroScale

Latest revision as of 19:22, 4 July 2022

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

-- Little bit of Lua for building tables for the Storm and Rabiah scales.
-- Mechanics have been re-ranked in the past, and it's probably interesting to track their drift.
-- Rather than force editors to track the newest one, let's see if we can't do it in code.

local MaroScale = {}

local sub, match, gsub = mw.ustring.sub, mw.ustring.match, mw.ustring.gsub

local MAX_ENTRIES = 500
-- A list of all sets which have been Standard-legal since the introduction of the Storm Scale (September 2012)
local LEGAL_EXPANSIONS = {
	["Return to Ravnica"]		= "2012-10-05",
	["Gatecrash"] 				= "2013-02-01",
	["Dragon's Maze"] 			= "2013-05-03",
	["Magic 2014"] 				= "2013-06-13",
	["Theros"] 					= "2013-09-27",
	["Born of the Gods"] 		= "2014-02-07",
	["Journey into Nyx"]		= "2014-05-02",
	["Magic 2015"] 				= "2014-07-18",
	["Khans of Tarkir"] 		= "2014-09-26",
	["Fate Reforged"] 			= "2015-01-23",
	["Dragons of Tarkir"] 		= "2015-03-17",
	["Magic Origins"] 			= "2015-07-15",
	["Battle for Zendikar"] 	= "2015-10-02",
	["Oath of the Gatewatch"] 	= "2016-01-22",
	["Shadows over Innistrad"] 	= "2016-04-08",
	["Eldritch Moon"] 			= "2016-06-22",
	["Kaladesh"] 				= "2016-09-30",
	["Aether Revolt"] 			= "2016-01-20",
	["Amonkhet"] 				= "2017-04-28",
	["Hour of Devastation"] 	= "2017-07-14",
}

local function generateLink(target, displayText)
	if displayText then
		return "[["..displayText.."|"..target.."]]"
	else
		return "[["..target.."]]"
	end
end

local function parseRatings(raw)
	local outputList = {}
	local newestDate, newestRating = 0, 0
	local rating, refDate, refString, t
	gsub(raw, "{(.-)}", function(a)
		rating, refDate, refString = match(a, "(%d+),([%d%-]+),(.+)")
		rating = tonumber(rating)
		
		-- Dates MUST be yyyy-mm-dd
		t = os.time({year=sub(refDate, 1,4), month=sub(refDate, 6,7), day=sub(refDate, 9,10),})
		if t > newestDate then
			newestDate = t
			newestRating = rating
		end
		
		table.insert(outputList, {text = rating..refString, t = t})
	end)
	
	return newestRating, outputList
end

local function addPrintings(timeline, printings)
	local releaseDate, t
	-- Comma-separated list
	gsub(printings, "([^,]+)", function(set)
		releaseDate = LEGAL_EXPANSIONS[set]
		
		-- The set name provided doesn't match a post-Storm Scale set
		if not releaseDate then return end
		
		-- Dates MUST be yyyy-mm-dd
		t = os.time({year=sub(releaseDate, 1,4), month=sub(releaseDate, 6,7), day=sub(releaseDate, 9,10),})
		
		table.insert(timeline, {text = generateLink(set), t = t})
	end)
	
	return timeline
end

local function sortTimeline(events)
	-- Sort all events into chronological order
	table.sort(events, function(a,b) return a.t < b.t end)
	return events
end

	
function MaroScale.TableBuilder(frame)
	local args = frame:getParent().args -- coming from one layer up
	
	-- Imitating navbox, here. I trust they know what they're doing.
	-- Read the arguments in the order they'll be output in, to make references number in the right order.
    local _
    _ = args.type
    _ = args.above
    for i = 1, MAX_ENTRIES do
        _ = args["name" .. tostring(i)]
        _ = args["entry" .. tostring(i)]
        _ = args["note" .. tostring(i)]
        _ = args["ratings" .. tostring(i)]
        _ = args["printings" .. tostring(i)]
    end
	
	-- Seriously this loop is entirely too clever
	local listnums = {}
	for k, v in pairs(args) do
		local listnum = match('' .. k, '^ratings(%d+)$')
		if listnum then table.insert(listnums, {num = tonumber(listnum), alpha = args["entry"..listnum]}) end
	end
	table.sort(listnums, function(a,b) return a.alpha < b.alpha end)

	
	-- Build the table header row
	local type = args.type
	local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
	tbl:tag("tr")
		:tag("th"):wikitext(type):done()
		:tag("th"):wikitext("Latest ranking"):done()
		:tag("th"):addClass("unsortable"):wikitext("Timeline"):done() -- Last column can't be sorted
	
	local hasNotes = false
	
	-- Reusable loop vars for performance
	local name, entry, note, ratings, printings
	local linkedEntry, lastRating, timeline
	local row, list, cellText
	for i, listnum in ipairs(listnums) do
		listnum = listnum.num
		-- Retrieve the relevant args for this row
		name, entry, note, ratings, printings = args["name"..listnum], args["entry"..listnum], args["note"..listnum], args["ratings"..listnum], args["printings"..listnum]
		
		-- Create a wikilink for the entry, using name as the target article if provided
		linkedEntry = generateLink(entry, name)
		if note then
			if not hasNotes then hasNotes = true end
			linkedEntry = linkedEntry .. frame:expandTemplate({title = "efn", args = { note }})
		end
		
		-- Decode the ratings into a table
		lastRating, timeline = parseRatings(ratings)
		-- Add any printings
		if printings then
			timeline = addPrintings(timeline, printings)
		end
		-- Sort chronologically
		timeline = sortTimeline(timeline)
		
		-- Make the row
		row = tbl:tag("tr")
		
		-- First cell
		row:tag("td"):wikitext(linkedEntry)
		
		-- Second cell
		row:tag("td"):wikitext(lastRating)
			
		-- Third cell
		--[[ Commented out by jerodast - let's just try regular wikitext.
		list = row:tag("td"):tag("ul"):cssText("display:block; margin-top:0; margin-left:0;")
		
		for j, event in ipairs(timeline) do
			if j ~= #timeline then
				list:tag("li"):cssText("display:inline-block;"):wikitext(event.text .. ",&nbsp;")
			else
				list:tag("li"):cssText("display:inline-block;"):wikitext(event.text)
			end
		end
		]]
	    list = {}
		for j, event in ipairs(timeline) do table.insert(list, event.text) end
		row:tag("td"):wikitext(table.concat(list,", "))
	end
	
	if hasNotes then
		return tostring(tbl) .. frame:expandTemplate({title = "notelist"})
	else
		return tbl
	end
end

return MaroScale