Module:SocialMedia: Difference between revisions
No edit summary |
// via Wikitext Extension for VSCode |
||
| (18 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- Module:SocialMedia | |||
-- Reusable social media component meant to be called from other modules | -- Reusable social media component meant to be called from other modules | ||
-- | -- ############################################################### | ||
-- Currently supported platforms are: | -- Currently supported platforms are: | ||
-- | -- (UPDATE THE LIST BETWEEN THE HOOK EMOJIS AS PLATFORMS GET ADDED OR REMOVED) | ||
-- 🪝Facebook, Github, Instagram, LinkedIn, Telegram, Threads, TikTok, X/Twitter, Youtube🪝 | |||
-- ############################################################### | |||
-- | |||
local sf = {} | local sf = {} | ||
local TemplateHelpers = require('Module:TemplateHelpers') | |||
-- This section defines the social platforms; can be added or deleted without consequence | -- This section defines the social platforms; can be added or deleted without consequence | ||
| Line 76: | Line 73: | ||
} | } | ||
-- Helper to find the first non-empty user handle from a param or table of params | -- Helper function to check if text is a full URL | ||
local function isFullUrl(text) | |||
return text and text:match("^https?://") ~= nil | |||
end | |||
-- Platform-specific normalizers table | |||
local normalizers = { | |||
linkedin = function(handle) | |||
-- If it's not a URL, return as is | |||
if not isFullUrl(handle) then return handle end | |||
-- Extract the path from the URL (case insensitive for linkedin.com) | |||
local path = handle:lower():match("linkedin%.com/(.+)") | |||
if not path then return handle end | |||
-- Handle /pub/ format | |||
if path:match("^pub/") then | |||
-- Extract the name part (first segment after /pub/) | |||
local name = path:match("^pub/([^/]+)") | |||
if name then return name end | |||
end | |||
-- Handle /in/ format - just extract the username | |||
if path:match("^in/") then | |||
return path:match("^in/([^/]+)") | |||
end | |||
-- If we can't parse it, return the original | |||
return handle | |||
end | |||
-- Add other platform normalizers as needed | |||
} | |||
-- Helper function to normalize handles based on platform | |||
local function normalizeHandle(platform, handle) | |||
-- Skip normalization if handle is nil or empty | |||
if not handle or handle == "" then return handle end | |||
-- Get the platform param (use first one if it's a table) | |||
local platformParam = platform.param | |||
if type(platformParam) == "table" then | |||
platformParam = platformParam[1] | |||
end | |||
-- If platform has a specific normalizer, use it | |||
if normalizers[platformParam] then | |||
return normalizers[platformParam](handle) | |||
end | |||
-- Default behavior: if it's a full URL, try to extract the handle | |||
if isFullUrl(handle) then | |||
-- Try to extract the handle from the URL based on the platform's prefix | |||
local prefix = platform.prefix:gsub("([%%%-%.])", "%%%1") -- Escape special pattern chars | |||
return handle:match(prefix .. "(.+)") or handle | |||
end | |||
-- If not a URL, return as is | |||
return handle | |||
end | |||
-- (Non-generalizable) Helper to find the first non-empty user handle from a param or table of params | |||
local function getUserHandle(args, param) | local function getUserHandle(args, param) | ||
local handle | local key, handle | ||
if type(param) == "string" then | if type(param) == "string" then | ||
handle = args | key, handle = TemplateHelpers.getFieldValue(args, { key = param }) | ||
else | else | ||
key, handle = TemplateHelpers.getFieldValue(args, { keys = param }) | |||
end | end | ||
if handle then | if handle and handle ~= "" then | ||
return mw.text.trim(handle) | return mw.text.trim(handle) | ||
end | end | ||
| Line 93: | Line 147: | ||
end | end | ||
-- Build a clickable icon link (24px) with alt text for accessibility: [[File: | -- Build a clickable icon link (24px) with alt text for accessibility: [[File:Name.svg|24px|class=...|alt=...|link=URL]] | ||
local function buildIconLink(iconFile, altText, url) | local function buildIconLink(iconFile, altText, url) | ||
return string.format("[[%s|24px|alt=%s|link=%s]]", iconFile, altText, url) | -- Add the reusable filter class to the image attributes | ||
return string.format("[[%s|24px|alt=%s|link=%s|class=filter-icon-green]]", iconFile, altText, url) | |||
end | end | ||
| Line 101: | Line 156: | ||
local function buildSocialRow(icons) | local function buildSocialRow(icons) | ||
local iconMarkup = table.concat({ | local iconMarkup = table.concat({ | ||
'<div class="social-icons | '<div class="social-icons link-open-external">', | ||
table.concat(icons, ""), | table.concat(icons, ""), | ||
'</div>' | '</div>' | ||
| Line 108: | Line 163: | ||
return table.concat({ | return table.concat({ | ||
"|-", | "|-", | ||
'| colspan="2" | ' | '| colspan="2" |', | ||
iconMarkup | |||
}, "\n") | }, "\n") | ||
end | end | ||
| Line 114: | Line 170: | ||
-- Main render function, takes a table of arguments (handles), returns wiki markup with social icons | -- Main render function, takes a table of arguments (handles), returns wiki markup with social icons | ||
function sf.render(args) | function sf.render(args) | ||
-- Early return if args is empty or nil | |||
if not args or next(args) == nil then | |||
return "" | |||
end | |||
-- Pre-allocate icons table based on maximum possible size (number of platforms) | |||
local icons = {} | local icons = {} | ||
icons[#socialPlatforms] = nil -- Pre-allocate table to avoid reallocation | |||
local iconCount = 0 | |||
for _, platform in ipairs(socialPlatforms) do | for _, platform in ipairs(socialPlatforms) do | ||
local handle = getUserHandle(args, platform.param) | local handle = getUserHandle(args, platform.param) | ||
if handle and handle ~= "" then | if handle and handle ~= "" then | ||
local url = platform.prefix .. handle | -- Normalize the handle based on platform | ||
local normalizedHandle = normalizeHandle(platform, handle) | |||
-- Check for special FULLURL: prefix from Python transformation | |||
local url | |||
if handle:match("^FULLURL:") then | |||
-- Extract the URL part after the FULLURL: prefix | |||
url = handle:gsub("^FULLURL:", "") | |||
-- If the handle is already a full URL, use it directly | |||
elseif isFullUrl(handle) and not isFullUrl(normalizedHandle) then | |||
-- We have a full URL that was successfully normalized to a handle | |||
url = platform.prefix .. normalizedHandle | |||
elseif isFullUrl(handle) then | |||
-- We have a full URL that couldn't be normalized, use it directly | |||
url = handle | |||
else | |||
-- We have a regular handle, use the standard approach | |||
url = platform.prefix .. handle | |||
end | |||
local iconLink = buildIconLink(platform.icon, platform.label, url) | local iconLink = buildIconLink(platform.icon, platform.label, url) | ||
table.insert | iconCount = iconCount + 1 | ||
icons[iconCount] = iconLink -- Direct index assignment is faster than table.insert | |||
end | end | ||
end | end | ||
-- If no handles were provided, return nothing | -- If no handles were provided, return nothing | ||
if #icons == 0 then | if #icons == 0 then | ||
return "" | return "" | ||
end | end | ||
-- Return a row | -- Return a row with a flex container for icons | ||
return buildSocialRow(icons) | return buildSocialRow(icons) | ||
end | end | ||
return sf | return sf | ||