Module:RelatedNews: Difference between revisions
From TwogPedia
(Created page with "local getArgs = require('Module:Arguments').getArgs local cargo = mw.ext.cargo local p = {} function p.main(frame) local args = getArgs(frame) local relatedTagsNews = getRelatedTagNews(args.tags, mw.title.getCurrentTitle().text) local newsItemContainer = mw.html.create('div'):addClass('related__news') local container = mw.html.create('div'):addClass('related__news__container '):node(mw.html.create('h3'):wikitext('Related news')):node(newsItemContainer) if...") |
No edit summary |
||
(5 intermediate revisions by 2 users not shown) | |||
Line 3: | Line 3: | ||
local p = {} | local p = {} | ||
local function sanitizeForSQL(input) | |||
if not input then return '' end | |||
-- Remove control characters | |||
input = mw.ustring.gsub(input, '[%z\1-\31\127]', '') | |||
-- Remove U+2060 (word joiner) and U+200B (zero-width space) | |||
input = mw.ustring.gsub(input, '[\226\129\160\226\128\139]', '') | |||
-- Correct way: double the quotes (SQL standard) | |||
input = mw.ustring.gsub(input, '"', '""') | |||
return input | |||
end | |||
function p.main(frame) | function p.main(frame) | ||
local args = getArgs(frame) | |||
local relatedTagsNews = getRelatedTagNews(args.tags, mw.title.getCurrentTitle().text) | |||
local newsItemContainer = mw.html.create('div'):addClass('related__news') | |||
local iconHtml = '[[File:News-icon.png|30px|alt=Related News Icon]]' | |||
local iconElement = mw.html.create('h3'):addClass('news-icon'):wikitext(iconHtml .. ' Related news') | |||
local titleContainer = mw.html.create('div'):addClass('related__news__title-container'):attr('style', 'display: flex; align-items: center;') | |||
titleContainer:node(iconElement) | |||
local viewAllElement = mw.html.create('div'):addClass('related__news__view-all'):attr('id', 'view-all-button'):wikitext('View All') | |||
titleContainer:node(viewAllElement) | |||
local container = mw.html.create('div'):addClass('related__news__container'):node(titleContainer):node(newsItemContainer) | |||
if #relatedTagsNews > 0 then | |||
for i = 1, #relatedTagsNews do | |||
addArticleToContainer(relatedTagsNews[i], newsItemContainer) | |||
end | |||
end | |||
if #relatedTagsNews < 5 then | |||
local relatedCatNews = getRelatedCatNews(args.categories, mw.title.getCurrentTitle().text, relatedTagsNews, 5 - #relatedTagsNews) | |||
for i = 1, #relatedCatNews do | |||
addArticleToContainer(relatedCatNews[i], newsItemContainer) | |||
end | |||
end | |||
return container | |||
end | end | ||
function addArticleToContainer(result, container) | function addArticleToContainer(result, container) | ||
local image = result.image or 'News placeholder.png' | |||
local link = result._pageName | |||
local category = result.category and mw.text.split(result.category, ',')[1] or 'Uncategorized' | |||
local categoryClassMap = { | |||
['News'] = 'news-category-news', | |||
['Transfer Market'] = 'news-category-transfer', | |||
['Drama'] = 'news-category-drama', | |||
['Business'] = 'news-category-business', | |||
['Sponsorships'] = 'news-category-sponsorships' | |||
} | |||
local categoryClass = categoryClassMap[category] or 'default-category-class' | |||
local date = result.date and formatDate(result.date) or 'Unknown date' | |||
local title = mw.html.create('div'):addClass('news-title-twogpedia'):wikitext(mw.ext.displaytitle.get(result._pageName)) | |||
local metaContainer = mw.html.create('div'):addClass('news-meta-container') | |||
local categoryElement = mw.html.create('p'):addClass('news-meta news-category-meta ' .. categoryClass):wikitext(category) | |||
local dateElement = mw.html.create('p'):addClass('news-meta news-date'):wikitext(date) | |||
metaContainer:node(categoryElement):node(dateElement) | |||
local contentSnippet = getContentSnippet(result.content) | |||
local contentElement = mw.html.create('p'):addClass('news-content'):wikitext(contentSnippet) | |||
local imageHtml = '[[File:' .. image .. '|link=' .. link .. '|800px|class=news-image|alt=News Image]]' | |||
local imageContainer = mw.html.create('div'):addClass('news-image-container'):wikitext(imageHtml) | |||
local newsItem = mw.html.create('div') | |||
:addClass('related__article') | |||
:node(imageContainer) | |||
:node(title) | |||
:node(contentElement) | |||
:node(metaContainer) | |||
container:node(newsItem) | |||
end | |||
function getContentSnippet(content) | |||
local words = mw.text.split(content, ' ') | |||
local snippet = table.concat(words, ' ', 1, math.min(20, #words)) | |||
return snippet .. ( #words > 20 and '...' or '' ) | |||
end | |||
function formatDate(dateStr) | |||
local year, month, day = dateStr:match("(%d+)%-(%d+)%-(%d+)") | |||
local time = os.time({year = year, month = month, day = day}) | |||
return os.date("%b %d, %Y", time) | |||
end | end | ||
function getRelatedTagNews(tags, pageName) | function getRelatedTagNews(tags, pageName) | ||
if not tags then return {} end | |||
pageName = sanitizeForSQL(pageName) | |||
local whereStr = '_pageName != "' .. pageName .. '" AND (' | |||
local tagsSplit = mw.text.split(tags, ',') | |||
for i = 1, #tagsSplit do | |||
if i > 1 then whereStr = whereStr .. ' OR ' end | |||
whereStr = whereStr .. 'tags HOLDS "' .. sanitizeForSQL(mw.text.trim(tagsSplit[i])) .. '"' | |||
end | |||
whereStr = whereStr .. ')' | |||
local tables = 'News' | |||
local fields = '_pageName, date, tags, image, category, content' | |||
local cargoArgs = { | |||
where = whereStr, | |||
orderBy = 'date DESC', | |||
limit = 5 | |||
} | |||
local results = cargo.query(tables, fields, cargoArgs) | |||
return results | |||
end | end | ||
function getRelatedCatNews(categories, pageName, missingAmount) | function getRelatedCatNews(categories, pageName, tagNews, missingAmount) | ||
if not categories then return {} end | |||
pageName = sanitizeForSQL(pageName) | |||
local whereStr = '' | |||
if #tagNews > 0 then | |||
for i = 1, #tagNews do | |||
whereStr = whereStr .. '_pageName != "' .. sanitizeForSQL(tagNews[i]._pageName) .. '" AND ' | |||
end | |||
end | |||
whereStr = whereStr .. '_pageName != "' .. pageName .. '" AND (' | |||
local catSplit = mw.text.split(categories, ',') | |||
for i = 1, #catSplit do | |||
if i > 1 then whereStr = whereStr .. ' OR ' end | |||
whereStr = whereStr .. 'category HOLDS "' .. sanitizeForSQL(mw.text.trim(catSplit[i])) .. '"' | |||
end | |||
whereStr = whereStr .. ')' | |||
local tables = 'News' | |||
local fields = '_pageName, date, tags, image, category, content' | |||
local cargoArgs = { | |||
where = whereStr, | |||
orderBy = 'date DESC', | |||
limit = missingAmount | |||
} | |||
local results = cargo.query(tables, fields, cargoArgs) | |||
return results | |||
end | end | ||
return p | return p |
Latest revision as of 21:13, 28 April 2025
Documentation for this module may be created at Module:RelatedNews/doc
local getArgs = require('Module:Arguments').getArgs
local cargo = mw.ext.cargo
local p = {}
local function sanitizeForSQL(input)
if not input then return '' end
-- Remove control characters
input = mw.ustring.gsub(input, '[%z\1-\31\127]', '')
-- Remove U+2060 (word joiner) and U+200B (zero-width space)
input = mw.ustring.gsub(input, '[\226\129\160\226\128\139]', '')
-- Correct way: double the quotes (SQL standard)
input = mw.ustring.gsub(input, '"', '""')
return input
end
function p.main(frame)
local args = getArgs(frame)
local relatedTagsNews = getRelatedTagNews(args.tags, mw.title.getCurrentTitle().text)
local newsItemContainer = mw.html.create('div'):addClass('related__news')
local iconHtml = '[[File:News-icon.png|30px|alt=Related News Icon]]'
local iconElement = mw.html.create('h3'):addClass('news-icon'):wikitext(iconHtml .. ' Related news')
local titleContainer = mw.html.create('div'):addClass('related__news__title-container'):attr('style', 'display: flex; align-items: center;')
titleContainer:node(iconElement)
local viewAllElement = mw.html.create('div'):addClass('related__news__view-all'):attr('id', 'view-all-button'):wikitext('View All')
titleContainer:node(viewAllElement)
local container = mw.html.create('div'):addClass('related__news__container'):node(titleContainer):node(newsItemContainer)
if #relatedTagsNews > 0 then
for i = 1, #relatedTagsNews do
addArticleToContainer(relatedTagsNews[i], newsItemContainer)
end
end
if #relatedTagsNews < 5 then
local relatedCatNews = getRelatedCatNews(args.categories, mw.title.getCurrentTitle().text, relatedTagsNews, 5 - #relatedTagsNews)
for i = 1, #relatedCatNews do
addArticleToContainer(relatedCatNews[i], newsItemContainer)
end
end
return container
end
function addArticleToContainer(result, container)
local image = result.image or 'News placeholder.png'
local link = result._pageName
local category = result.category and mw.text.split(result.category, ',')[1] or 'Uncategorized'
local categoryClassMap = {
['News'] = 'news-category-news',
['Transfer Market'] = 'news-category-transfer',
['Drama'] = 'news-category-drama',
['Business'] = 'news-category-business',
['Sponsorships'] = 'news-category-sponsorships'
}
local categoryClass = categoryClassMap[category] or 'default-category-class'
local date = result.date and formatDate(result.date) or 'Unknown date'
local title = mw.html.create('div'):addClass('news-title-twogpedia'):wikitext(mw.ext.displaytitle.get(result._pageName))
local metaContainer = mw.html.create('div'):addClass('news-meta-container')
local categoryElement = mw.html.create('p'):addClass('news-meta news-category-meta ' .. categoryClass):wikitext(category)
local dateElement = mw.html.create('p'):addClass('news-meta news-date'):wikitext(date)
metaContainer:node(categoryElement):node(dateElement)
local contentSnippet = getContentSnippet(result.content)
local contentElement = mw.html.create('p'):addClass('news-content'):wikitext(contentSnippet)
local imageHtml = '[[File:' .. image .. '|link=' .. link .. '|800px|class=news-image|alt=News Image]]'
local imageContainer = mw.html.create('div'):addClass('news-image-container'):wikitext(imageHtml)
local newsItem = mw.html.create('div')
:addClass('related__article')
:node(imageContainer)
:node(title)
:node(contentElement)
:node(metaContainer)
container:node(newsItem)
end
function getContentSnippet(content)
local words = mw.text.split(content, ' ')
local snippet = table.concat(words, ' ', 1, math.min(20, #words))
return snippet .. ( #words > 20 and '...' or '' )
end
function formatDate(dateStr)
local year, month, day = dateStr:match("(%d+)%-(%d+)%-(%d+)")
local time = os.time({year = year, month = month, day = day})
return os.date("%b %d, %Y", time)
end
function getRelatedTagNews(tags, pageName)
if not tags then return {} end
pageName = sanitizeForSQL(pageName)
local whereStr = '_pageName != "' .. pageName .. '" AND ('
local tagsSplit = mw.text.split(tags, ',')
for i = 1, #tagsSplit do
if i > 1 then whereStr = whereStr .. ' OR ' end
whereStr = whereStr .. 'tags HOLDS "' .. sanitizeForSQL(mw.text.trim(tagsSplit[i])) .. '"'
end
whereStr = whereStr .. ')'
local tables = 'News'
local fields = '_pageName, date, tags, image, category, content'
local cargoArgs = {
where = whereStr,
orderBy = 'date DESC',
limit = 5
}
local results = cargo.query(tables, fields, cargoArgs)
return results
end
function getRelatedCatNews(categories, pageName, tagNews, missingAmount)
if not categories then return {} end
pageName = sanitizeForSQL(pageName)
local whereStr = ''
if #tagNews > 0 then
for i = 1, #tagNews do
whereStr = whereStr .. '_pageName != "' .. sanitizeForSQL(tagNews[i]._pageName) .. '" AND '
end
end
whereStr = whereStr .. '_pageName != "' .. pageName .. '" AND ('
local catSplit = mw.text.split(categories, ',')
for i = 1, #catSplit do
if i > 1 then whereStr = whereStr .. ' OR ' end
whereStr = whereStr .. 'category HOLDS "' .. sanitizeForSQL(mw.text.trim(catSplit[i])) .. '"'
end
whereStr = whereStr .. ')'
local tables = 'News'
local fields = '_pageName, date, tags, image, category, content'
local cargoArgs = {
where = whereStr,
orderBy = 'date DESC',
limit = missingAmount
}
local results = cargo.query(tables, fields, cargoArgs)
return results
end
return p
No categories