Module:BuildVersionTree
From Seven Sages of Rome
Documentation for this module may be created at Module:BuildVersionTree/doc
-- Module:VersionTree
local p = {}
-- Helper function to build a tree structure from flat data
local function buildTree(versions, parentField)
local tree = {}
local nodes = {}
-- First pass: Create all nodes
for _, version in pairs(versions) do
local title = version[1]
nodes[title] = {
title = title,
children = {},
processed = false
}
end
-- Second pass: Build relationships
for _, version in pairs(versions) do
local title = version[1]
local parent = version[parentField]
if parent and parent[1] and nodes[parent[1]] then
-- If it has a valid parent, add it as a child
table.insert(nodes[parent[1]].children, nodes[title])
else
-- If no parent or invalid parent, it's a root node
table.insert(tree, nodes[title])
end
end
return tree
end
-- Helper function to generate unique IDs for nodes
local function generateId(text)
return 'node-' .. mw.uri.encode(text):gsub('%%', '-')
end
-- Helper function to render a tree node and its children
local function renderNode(node, level)
local result = {}
-- Generate unique ID for this node
local nodeId = generateId(node.title)
-- Create node container
table.insert(result, string.format('<div class="tree-node level-%d" id="%s">', level, nodeId))
-- Add node content
table.insert(result, '<div class="node-content">')
table.insert(result, string.format('<div class="node-box">[[%s]]</div>', node.title))
table.insert(result, '</div>')
if #node.children > 0 then
-- Add container for children
table.insert(result, '<div class="node-children">')
-- Sort children by title
table.sort(node.children, function(a, b)
return a.title < b.title
end)
-- Render children
for _, child in ipairs(node.children) do
table.insert(result, renderNode(child, level + 1))
end
table.insert(result, '</div>')
end
table.insert(result, '</div>')
return table.concat(result, '\n')
end
-- Main function to process the versions and generate tree view
function p.getTree(frame)
local versions = mw.smw.ask({
"[[Category:Version||Secondary Version]]",
"?Has Parent Version"
})
if not versions then
return "SMW query returned no results."
end
-- Build tree
local tree = buildTree(versions, "Has Parent Version")
-- Sort root nodes
table.sort(tree, function(a, b)
return a.title < b.title
end)
-- Create output with CSS
local result = {[[
<div class="version-tree">
<style>
.version-tree {
text-align: center;
padding: 20px;
}
.tree-node {
display: inline-block;
vertical-align: top;
text-align: center;
padding: 10px;
position: relative;
}
.node-content {
display: inline-block;
vertical-align: top;
padding: 5px;
}
.node-box {
border: 2px solid #3366cc;
border-radius: 5px;
padding: 8px 15px;
background-color: white;
display: inline-block;
margin: 0 5px;
}
.node-children {
padding-top: 20px;
position: relative;
}
.node-children:before {
content: "";
position: absolute;
top: 0;
left: 50%;
border-left: 2px solid #3366cc;
height: 20px;
}
.tree-node .node-children .tree-node:before {
content: "";
position: absolute;
top: 0;
left: 50%;
border-left: 2px solid #3366cc;
height: 20px;
}
.node-children .tree-node {
position: relative;
}
.node-children .tree-node:before {
content: "";
position: absolute;
top: -20px;
left: 50%;
border-left: 2px solid #3366cc;
height: 20px;
}
.node-children .tree-node:first-child:before {
border: none;
}
.node-children .tree-node:after {
content: "";
position: absolute;
top: -20px;
left: 50%;
border-top: 2px solid #3366cc;
width: 50%;
}
.node-children .tree-node:first-child:after {
border-radius: 0 5px 0 0;
border-right: 2px solid #3366cc;
}
.node-children .tree-node:last-child:after {
border-radius: 5px 0 0 0;
border-left: 2px solid #3366cc;
}
</style>
]]}
-- Render each root node
for _, node in ipairs(tree) do
table.insert(result, renderNode(node, 0))
end
table.insert(result, '</div>')
return table.concat(result, '\n')
end
return p