Module:RelatedNews: Difference between revisions
From TwogPedia
No edit summary Tag: Manual revert |
Speed Related news: skip displaytitle.get, 400px thumbs, drop unused tags field |
||
| Line 6: | Line 6: | ||
local function sanitizeForSQL(input) | local function sanitizeForSQL(input) | ||
if not input then return '' end | if not input then return '' end | ||
input = mw.ustring.gsub(input, '[%z\1-\31\127]', '') | input = mw.ustring.gsub(input, '[%z\1-\31\127]', '') | ||
input = mw.ustring.gsub(input, '[\226\129\160\226\128\139]', '') | input = mw.ustring.gsub(input, '[\226\129\160\226\128\139]', '') | ||
input = mw.ustring.gsub(input, '"', '""') | input = mw.ustring.gsub(input, '"', '""') | ||
return input | return input | ||
end | end | ||
function p.main(frame) | local function displayName(pageName) | ||
local name = pageName or '' | |||
name = mw.ustring.gsub(name, '^News/', '') | |||
name = mw.ustring.gsub(name, '_', ' ') | |||
return name | |||
end | |||
function p.main(frame) | |||
local args = getArgs(frame) | local args = getArgs(frame) | ||
local relatedTagsNews = getRelatedTagNews(args.tags, mw.title.getCurrentTitle().text) | local relatedTagsNews = getRelatedTagNews(args.tags, mw.title.getCurrentTitle().text) | ||
local newsItemContainer = mw.html.create('div'):addClass('related__news') | local newsItemContainer = mw.html.create('div'):addClass('related__news') | ||
local iconHtml = '[[File:News-icon.png|30px|alt=Related News Icon]]' | local iconHtml = '[[File:News-icon.png|30px|alt=Related News Icon]]' | ||
local iconElement = mw.html.create('h3'):addClass('news-icon'):wikitext(iconHtml .. '<span style="margin-left: 10px;">Related news</span>') | local iconElement = mw.html.create('h3'):addClass('news-icon'):wikitext(iconHtml .. '<span style="margin-left: 10px;">Related news</span>') | ||
local titleContainer = mw.html.create('div'):addClass('related__news__title-container'):attr('style', 'display: flex; align-items: center;') | local titleContainer = mw.html.create('div'):addClass('related__news__title-container'):attr('style', 'display: flex; align-items: center;') | ||
titleContainer:node(iconElement) | titleContainer:node(iconElement) | ||
local viewAllElement = mw.html.create('span') | |||
:addClass('related__news__view-all') | :addClass('related__news__view-all') | ||
:attr('id', 'view-all-button') | :attr('id', 'view-all-button') | ||
| Line 42: | Line 46: | ||
end | end | ||
end | end | ||
if #relatedTagsNews < 5 then | if #relatedTagsNews < 5 then | ||
local relatedCatNews = getRelatedCatNews(args.categories, mw.title.getCurrentTitle().text, relatedTagsNews, 5 - #relatedTagsNews) | local relatedCatNews = getRelatedCatNews(args.categories, mw.title.getCurrentTitle().text, relatedTagsNews, 5 - #relatedTagsNews) | ||
| Line 67: | Line 71: | ||
local categoryClass = categoryClassMap[category] or 'default-category-class' | local categoryClass = categoryClassMap[category] or 'default-category-class' | ||
local date = result.date and formatDate(result.date) or 'Unknown date' | local date = result.date and formatDate(result.date) or 'Unknown date' | ||
local title = mw.html.create('div') | |||
:addClass('news-title-twogpedia') | |||
:wikitext('[[' .. result._pageName .. '|' .. displayName(result._pageName) .. ']]') | |||
local metaContainer = mw.html.create('div'):addClass('news-meta-container') | 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 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) | local dateElement = mw.html.create('p'):addClass('news-meta news-date'):wikitext(date) | ||
metaContainer:node(categoryElement):node(dateElement) | metaContainer:node(categoryElement):node(dateElement) | ||
| Line 83: | Line 87: | ||
local contentElement = mw.html.create('p'):addClass('news-content'):wikitext(contentSnippet) | local contentElement = mw.html.create('p'):addClass('news-content'):wikitext(contentSnippet) | ||
local imageHtml = '[[File:' .. image .. '|link=' .. link .. '| | -- 400px matches related-card CSS; 800px forced a heavy thumb transform on parse. | ||
local imageHtml = '[[File:' .. image .. '|link=' .. link .. '|400px|class=news-image|alt=News Image]]' | |||
local imageContainer = mw.html.create('div'):addClass('news-image-container'):wikitext(imageHtml) | local imageContainer = mw.html.create('div'):addClass('news-image-container'):wikitext(imageHtml) | ||
local newsItem = mw.html.create('div') | local newsItem = mw.html.create('div') | ||
:addClass('related__article') | :addClass('related__article') | ||
| Line 101: | Line 106: | ||
return '' | return '' | ||
end | end | ||
local plain = mw.ustring.gsub(content, '<[^>]+>', '') | local plain = mw.ustring.gsub(content, '<[^>]+>', '') | ||
plain = mw.ustring.gsub(plain, "'''", '') | plain = mw.ustring.gsub(plain, "'''", '') | ||
plain = mw.ustring.gsub(plain, "''", '') | plain = mw.ustring.gsub(plain, "''", '') | ||
plain = mw.ustring.gsub(plain, '^%s+', '') | plain = mw.ustring.gsub(plain, '^%s+', '') | ||
plain = mw.ustring.gsub(plain, '%s+$', '') | plain = mw.ustring.gsub(plain, '%s+$', '') | ||
local words = mw.text.split(plain, '%s+') | local words = mw.text.split(plain, '%s+') | ||
local maxWords = 20 | local maxWords = 20 | ||
| Line 115: | Line 120: | ||
table.insert(snippetWords, words[i]) | table.insert(snippetWords, words[i]) | ||
end | end | ||
local snippet = table.concat(snippetWords, ' ') | local snippet = table.concat(snippetWords, ' ') | ||
if #words > maxWords then | if #words > maxWords then | ||
snippet = snippet .. '...' | snippet = snippet .. '...' | ||
end | end | ||
return snippet | return snippet | ||
end | end | ||
| Line 132: | Line 137: | ||
function getRelatedTagNews(tags, pageName) | function getRelatedTagNews(tags, pageName) | ||
if not tags then return {} end | if not tags then return {} end | ||
pageName = sanitizeForSQL(pageName) | pageName = sanitizeForSQL(pageName) | ||
local whereStr = '_pageName != "' .. pageName .. '" AND (' | local whereStr = '_pageName != "' .. pageName .. '" AND (' | ||
local tagsSplit = mw.text.split(tags, ',') | local tagsSplit = mw.text.split(tags, ',') | ||
for i = 1, #tagsSplit do | for i = 1, #tagsSplit do | ||
| Line 144: | Line 149: | ||
local tables = 'News' | local tables = 'News' | ||
local fields = '_pageName, date | local fields = '_pageName, date, image, category, content' | ||
local cargoArgs = { | local cargoArgs = { | ||
where = whereStr, | where = whereStr, | ||
| Line 167: | Line 172: | ||
end | end | ||
whereStr = whereStr .. '_pageName != "' .. pageName .. '" AND (' | whereStr = whereStr .. '_pageName != "' .. pageName .. '" AND (' | ||
local catSplit = mw.text.split(categories, ',') | local catSplit = mw.text.split(categories, ',') | ||
for i = 1, #catSplit do | for i = 1, #catSplit do | ||
| Line 176: | Line 181: | ||
local tables = 'News' | local tables = 'News' | ||
local fields = '_pageName, date | local fields = '_pageName, date, image, category, content' | ||
local cargoArgs = { | local cargoArgs = { | ||
where = whereStr, | where = whereStr, | ||
Revision as of 05:30, 31 August 2026
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
input = mw.ustring.gsub(input, '[%z\1-\31\127]', '')
input = mw.ustring.gsub(input, '[\226\129\160\226\128\139]', '')
input = mw.ustring.gsub(input, '"', '""')
return input
end
local function displayName(pageName)
local name = pageName or ''
name = mw.ustring.gsub(name, '^News/', '')
name = mw.ustring.gsub(name, '_', ' ')
return name
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 .. '<span style="margin-left: 10px;">Related news</span>')
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('span')
:addClass('related__news__view-all')
:attr('id', 'view-all-button')
:wikitext('[[News|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('[[' .. result._pageName .. '|' .. displayName(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)
-- 400px matches related-card CSS; 800px forced a heavy thumb transform on parse.
local imageHtml = '[[File:' .. image .. '|link=' .. link .. '|400px|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)
if not content or content == '' then
return ''
end
local plain = mw.ustring.gsub(content, '<[^>]+>', '')
plain = mw.ustring.gsub(plain, "'''", '')
plain = mw.ustring.gsub(plain, "''", '')
plain = mw.ustring.gsub(plain, '^%s+', '')
plain = mw.ustring.gsub(plain, '%s+$', '')
local words = mw.text.split(plain, '%s+')
local maxWords = 20
local snippetWords = {}
for i = 1, math.min(maxWords, #words) do
table.insert(snippetWords, words[i])
end
local snippet = table.concat(snippetWords, ' ')
if #words > maxWords then
snippet = snippet .. '...'
end
return snippet
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, 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, 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