Module:SocialMedia: Difference between revisions

minor rev // via Wikitext Extension for VSCode
// via Wikitext Extension for VSCode
 
(16 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- Module:SocialMedia
-- Module:SocialMedia
-- Reusable social media component meant to be called from other modules


--------------------------------------------------------------------------------
-- ###############################################################
-- Lines 5 and 6 get transcluded based on their position in this Module, so do not move them!
-- Currently supported platforms are:
-- Currently supported platforms are:
-- Facebook, Github, Instagram, LinkedIn, Telegram, Threads, TikTok, X/Twitter, Youtube
-- (UPDATE THE LIST BETWEEN THE HOOK EMOJIS AS PLATFORMS GET ADDED OR REMOVED)
-- (Update Line 6 as plaforms get added or removed)
-- 🪝Facebook, Github, Instagram, LinkedIn, Telegram, Threads, TikTok, X/Twitter, Youtube🪝
--------------------------------------------------------------------------------
-- ###############################################################
 
-- Reusable social media component meant to be called from other modules
 
--------------------------------------------------------------------------------
-- ! ONLY START EDITING FROM THIS POINT ONWARDS !
--------------------------------------------------------------------------------


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 78: 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[param]
         key, handle = TemplateHelpers.getFieldValue(args, { key = param })
     else
     else
         for _, alias in ipairs(param) do
         key, handle = TemplateHelpers.getFieldValue(args, { keys = param })
            handle = args[alias]
            if handle and handle ~= "" then break end
        end
     end
     end
     if handle then
     if handle and handle ~= "" then
         return mw.text.trim(handle)
         return mw.text.trim(handle)
     end
     end
Line 95: Line 147:
end
end


-- Build a clickable icon link (24px) with alt text for accessibility: [[File:Something.svg|24px|alt=ALT_TEXT|link=URL]]
-- 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 103: Line 156:
local function buildSocialRow(icons)
local function buildSocialRow(icons)
     local iconMarkup = table.concat({
     local iconMarkup = table.concat({
         '<div class="social-icons external-social" style="display: flex; flex-wrap: wrap; gap: 0.5em; margin-top: 0.2em; justify-content: center;">',
         '<div class="social-icons link-open-external">',
             table.concat(icons, ""),
             table.concat(icons, ""),
         '</div>'
         '</div>'
Line 110: Line 163:
     return table.concat({
     return table.concat({
         "|-",
         "|-",
         '| colspan="2" | ' .. iconMarkup
         '| colspan="2" |',
        iconMarkup
     }, "\n")
     }, "\n")
end
end
Line 116: 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(icons, iconLink)
             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 that fits nicely in the template, with a flex container for icons
     -- Return a row with a flex container for icons
     return buildSocialRow(icons)
     return buildSocialRow(icons)
end
end


return sf
return sf