Module:RelatedNews: Difference between revisions

From TwogPedia
mNo edit summary
No edit summary
 
(4 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 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 container = mw.html.create('div'):addClass('related__news__container '):node(mw.html.create('h3'):wikitext('Related news')):node(newsItemContainer)
 
 
    local iconHtml = '[[File:News-icon.png|30px|alt=Related News Icon]]'
if #relatedTagsNews > 0 then
    local iconElement = mw.html.create('h3'):addClass('news-icon'):wikitext(iconHtml .. ' Related news')
for i = 1, #relatedTagsNews do
   
addArticleToContainer(relatedTagsNews[i], newsItemContainer)
    local titleContainer = mw.html.create('div'):addClass('related__news__title-container'):attr('style', 'display: flex; align-items: center;')
end
    titleContainer:node(iconElement)
end
 
    local viewAllElement = mw.html.create('div'):addClass('related__news__view-all'):attr('id', 'view-all-button'):wikitext('View All')
    titleContainer:node(viewAllElement)
-- If less than 5 related tag news were found, then fill with news from categories
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
    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 image = result.image or 'News placeholder.png'
    local link = result._pageName
local title = mw.html.create('div'):wikitext(mw.ext.displaytitle.get(result._pageName))
    local category = result.category and mw.text.split(result.category, ',')[1] or 'Uncategorized'
local newsItem = mw.html.create('div'):addClass('related__article'):wikitext('[[File:'.. image .. '|link=' .. result._pageName .. '|800x450px]]'):node(title)
 
container:node(newsItem)
    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
    if not tags then return {} end
   
local whereStr = '_pageName != "' .. pageName .. '" AND ('  
    pageName = sanitizeForSQL(pageName)
local tagsSplit = mw.text.split(tags, ',')
   
for i = 1, #tagsSplit do
    local whereStr = '_pageName != "' .. pageName .. '" AND ('  
if i > 1 then whereStr = whereStr .. ' OR ' end
    local tagsSplit = mw.text.split(tags, ',')
whereStr = whereStr .. 'tags HOLDS "' .. mw.text.trim(tagsSplit[i]) .. '"'
    for i = 1, #tagsSplit do
end
        if i > 1 then whereStr = whereStr .. ' OR ' end
whereStr = whereStr .. ')'
        whereStr = whereStr .. 'tags HOLDS "' .. sanitizeForSQL(mw.text.trim(tagsSplit[i])) .. '"'
    end
    whereStr = whereStr .. ')'


local tables = 'News'
    local tables = 'News'
local fields = '_pageName, date, tags, image'
    local fields = '_pageName, date, tags, image, category, content'
local cargoArgs = {
    local cargoArgs = {
where = whereStr,
        where = whereStr,
orderBy = 'date DESC',
        orderBy = 'date DESC',
limit = 5
        limit = 5
}
    }
local results = cargo.query(tables, fields, cargoArgs)
    local results = cargo.query(tables, fields, cargoArgs)
return results
    return results
end
end


function getRelatedCatNews(categories, pageName, tagNews, missingAmount)
function getRelatedCatNews(categories, pageName, tagNews, missingAmount)
if not categories then return {} end
    if not categories then return {} end
local whereStr = ''
 
    pageName = sanitizeForSQL(pageName)
if #tagNews > 0 then
 
for i = 1, #tagNews do
    local whereStr = ''
whereStr = '_pageName != "' .. tagNews[i]._pageName .. '" AND '
 
end
    if #tagNews > 0 then
end
        for i = 1, #tagNews do
            whereStr = whereStr .. '_pageName != "' .. sanitizeForSQL(tagNews[i]._pageName) .. '" AND '
local whereStr = whereStr .. '_pageName != "' .. pageName .. '" AND ('  
        end
local catSplit = mw.text.split(categories, ',')
    end
for i = 1, #catSplit do
 
if i > 1 then whereStr = whereStr .. ' OR ' end
    whereStr = whereStr .. '_pageName != "' .. pageName .. '" AND ('  
whereStr = whereStr .. 'category HOLDS "' .. mw.text.trim(catSplit[i]) .. '"'
    local catSplit = mw.text.split(categories, ',')
end
    for i = 1, #catSplit do
whereStr = whereStr .. ')'
        if i > 1 then whereStr = whereStr .. ' OR ' end
mw.log(whereStr)
        whereStr = whereStr .. 'category HOLDS "' .. sanitizeForSQL(mw.text.trim(catSplit[i])) .. '"'
local tables = 'News'
    end
local fields = '_pageName, date, tags, image'
    whereStr = whereStr .. ')'
local cargoArgs = {
 
where = whereStr,
    local tables = 'News'
orderBy = 'date DESC',
    local fields = '_pageName, date, tags, image, category, content'
limit = missingAmount
    local cargoArgs = {
}
        where = whereStr,
local results = cargo.query(tables, fields, cargoArgs)
        orderBy = 'date DESC',
return results
        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