Module:ServicesList
From MaRDI portal
Documentation for this module may be created at Module:ServicesList/doc
-- Required module containing helper methods
local helper = require('Module:HelperMethods')
-- Required modules for SPARQL queries and HTML table generation
local sparql = require('SPARQL')
local mwHtml = require('mw.html')
-- Main table to hold all functions
local p = {}
-- Helper: convert a service name to a URL-safe anchor id
local function toAnchorId(name)
return name:lower()
:gsub("%s+", "-")
:gsub("[^%a%d%-]", "")
end
function p.convertJsonToHTMLCards(jsonResults, landingpage)
local isLandingPage = (landingpage == "true")
local resultsHTML = '<div class="mardi-service-grid">'
if jsonResults and jsonResults.results and jsonResults.results.bindings then
local bindings = jsonResults.results.bindings
for i = 0, #bindings do
local baseEntity = "https://portal.mardi4nfdi.de/entity/"
local binding = bindings[i]
-- Extract fields from the bindings
local name = binding.name and binding.name.value or "Unnamed Service"
local category = binding.categories and binding.categories.value or "No Category"
local maintainer = binding.maintainers and binding.maintainers.value or "Unknown maintainer"
local maintainer_url = binding.maintainer_url_sample and binding.maintainer_url_sample.value or " "
local description = binding.description and binding.description.value or "No description available."
local summary = binding.summary and binding.summary.value or "No summary available."
local status = binding.status and binding.status.value or "No status available."
local link = binding.item and mw.wikibase.getSitelink( string.sub(binding.item.value, #baseEntity + 1) ) or "#"
local imageName = binding.icon and binding.icon.value or "File:nologo.jpg"
imageName = imageName:match("File:.*") or imageName
local image = "[[" .. imageName .. "|200px|left|link=]]"
local anchorId = toAnchorId(name)
if isLandingPage then
description = description:gsub("\\N", "\n")
description = description:gsub("##", "")
end
-- Teaser: first 120 chars of summary (fallback: description)
local teaserSource = summary ~= "No summary available." and summary or description
local teaser = string.sub(teaserSource, 1, 120)
if #teaserSource > 60 then
teaser = teaser .. "..."
end
-- Open card
resultsHTML = resultsHTML .. string.format(
'<div id="%s" class="mardi-service-card"><div class="mardi-card-inner">',
anchorId
)
-- Image column
resultsHTML = resultsHTML .. '<div class="mardi-card-image">' .. image .. '</div>'
-- Text column (open)
resultsHTML = resultsHTML .. '<div class="mardi-card-body">'
if not isLandingPage then
local description_rendered = helper.markdownToMediawiki("\\N" .. description)
resultsHTML = resultsHTML .. string.format([=[
<h3>[[ %s | %s ]]</h3>
<div class="mardi-card-subtitle">%s (%s)</div>
<div class="mardi-card-description">%s</div>
<div class="mardi-card-maintainer">Maintained by: [%s %s]</div>
]=], link, name, category, status, description_rendered, maintainer_url, maintainer)
end
if isLandingPage then
resultsHTML = resultsHTML .. string.format([=[
<h3>%s</h3>
<div class="mardi-card-subtitle">%s</div>
<p class="mardi-card-description">%s</p>
<div class="mardi-card-more">[[ %s | Discover more ]]</div>
]=], name, category, teaser, link)
end
-- Close text column, inner layout, card
resultsHTML = resultsHTML .. '</div></div></div>'
end
end
resultsHTML = resultsHTML .. '</div>'
return resultsHTML
end
-- Function to build the list
function p.buildServiceList(frame)
local landingpage = frame.args["landingpage"] or "false"
local sparqlQuery = [[
PREFIX wdt: <https://portal.mardi4nfdi.de/prop/direct/>
PREFIX wd: <https://portal.mardi4nfdi.de/entity/>
SELECT
?item
?name
?icon
?description
?summary
?status
(GROUP_CONCAT(DISTINCT ?maintainer; SEPARATOR=" | ") AS ?maintainers)
(SAMPLE(?maintainer_url) AS ?maintainer_url_sample)
(GROUP_CONCAT(DISTINCT ?category; SEPARATOR=" | ") AS ?categories)
WHERE {
?item wdt:P1460 wd:Q6503324 .
?item rdfs:label ?name .
FILTER(LANG(?name) = "en")
OPTIONAL {
?item wdt:P19 ?maintainer_url .
?maintainer_url rdfs:label ?maintainer .
FILTER(LANG(?maintainer) = "en")
}
OPTIONAL {
?item wdt:P1641 ?category_url .
?category_url rdfs:label ?category .
FILTER(LANG(?category) = "en")
}
OPTIONAL { ?item wdt:P1640 ?icon . }
OPTIONAL { ?item wdt:P1459 ?description . }
OPTIONAL { ?item wdt:P1638 ?summary . }
OPTIONAL {
?item wdt:P230 ?status_url .
?status_url rdfs:label ?status .
FILTER(LANG(?status) = "en")
}
}
GROUP BY ?item ?name ?icon ?description ?summary ?status
]]
local jsonResults = sparql.runQuery(sparqlQuery)
if jsonResults and jsonResults.error then
mw.log("Error in SPARQL query: " .. tostring(jsonResults.error))
return nil
end
if not jsonResults then
return "Could not fetch data."
end
if helper.countElementsInBindings(jsonResults.results.bindings) == 0 then
return "No records found."
end
return p.convertJsonToHTMLCards(jsonResults, landingpage)
end
return p