Module:Sister project links
MyWikiBiz, Author Your Legacy — Monday November 25, 2024
Jump to navigationJump to searchTemplate:High use Template:Lua Implements {{Sister project links}}
See {{Sister project links/testcases}} for test cases.
-- Module to create sister project link box local getArgs = require('Module:Arguments').getArgs local commonsLink = require('Module:Commons link') local p = {} -- Function to canonicalize string -- search for variants of "yes", and "no", and transform -- them into a standard form (like [[Template:YesNo]]) -- Argument: -- s --- input string -- Result: -- {x,y} list of length 2 -- x = nil if s is canonicalized, otherwise has trimmed s -- y = canonical form of s (true if "yes" or other, false if "no", nil if blank) local function canonicalize(s) if s == nil then return {nil, nil} end s = mw.text.trim(tostring(s)) if s == "" then return {nil, nil} end lowerS = s:lower() -- Check for various forms of "yes" if lowerS == 'yes' or lowerS == 'y' or lowerS == 't' or lowerS == '1' or lowerS == 'true' or lowerS == 'on' then return {nil, true} end -- Check for various forms of "no" if lowerS == 'no' or lowerS == 'n' or lowerS == 'f' or lowerS == '0' or lowerS == 'false' or lowerS == 'off'then return {nil, false} end -- Neither yes nor no recognized, leave string trimmed return {s, true} end -- Merge two or more canonicalized argument lists -- Arguments: -- argList = list of canonicalized arguments -- noAll = if true, return no when all argList is no. -- otherwise, return blank when all argList is blank local function mergeArgs(argList,noAll) local test = nil -- default, return blank if all blank if noAll then test = false -- return no if all no end local allSame = true -- Search through string for first non-no or non-blank for _, arg in ipairs(argList) do if arg[2] then return arg -- found non-no and non-blank, return it end -- test to see if argList is all blank / no allSame = allSame and (arg[2] == test) end -- if all blank / no, return blank / no if allSame then return {nil, test} -- all match no/blank, return it end -- otherwise, return no / blank if noAll then return {nil, nil} end return {nil, false} end -- Function to get sitelink for a wiki -- Arguments: -- wiki = db name of wiki to lookup -- qid = QID of entity to search for, current page entity by default local function getSitelink(wiki,qid) qid = qid or mw.wikibase.getEntityIdForCurrentPage() qid = qid and qid:upper() -- return nil if some sort of lookup failure return qid and mw.wikibase.getSitelink(qid,wiki) end local wdMismatch = nil local wdNamespace = nil local wdHidden = nil local defaultSearch = nil -- Function to generate the sister link itself -- Arguments: -- args = argument table for function -- args[1] = canonicalized page to fetch -- args.default = link when blank -- args.auto = new auto mode (don't fall back to search) -- args.sitelink = wikidata sitelink (if available) -- args.sisterDbName = DB name of sister site (to get sitelink) -- args.qid = QID of entity -- args.search = fallback string to search for -- args.sisterPrefix = wikitext prefix for sister site -- args.information = type of info sister site contains -- args.sisterName = friendly human name of sister site function p._sisterLink(args) if args[1][2] == false or (not args.default and args[1][2] == nil) then return nil --- either editor specified "no", or "blank" (and default=no), then skip this sister end local sitelink = args.sitelink or (args.sisterDbName and getSitelink(args.sisterDbName,args.qid)) if args.auto and not sitelink and args[1][2] == nil then return nil --- in auto mode, if link is blank and no sitelink, then skip end -- fallback order of sister link: first specified page, then wikidata, then search local link = args[1][1] or sitelink or (args.search and "Special:"..args.search) if not link then return nil --- no link found, just skip end -- update state for tracking categories if args[1][1] and sitelink then -- transform supplied page name to be in wiki-format local page = mw.ustring.gsub(args[1][1],"_"," ") page = mw.ustring.sub(page,1,1):upper()..mw.ustring.sub(page,2) local pageNS = mw.ustring.match(page,"^([^:]+):") local sitelinkNS = mw.ustring.match(sitelink,"^([^:]+):") if page == sitelink then wdHidden = args.sisterPrefix elseif pageNS ~= sitelinkNS then wdNamespace = args.sisterPrefix else wdMismatch = args.sisterPrefix end -- if no page link, nor a wikidata entry, and search is on, then warn elseif not (args[1][2] or sitelink) and args.search then defaultSearch = args.sisterPrefix end return "[["..args.sisterPrefix..":"..link.."|"..args.information .."]] from "..args.sisterName end -- Function to generate HTML for one sister link -- Arguments: -- container = parent HTML object -- args = argument table for function -- args[1] = canonicalized page to fetch -- args.default = link when blank -- args.auto = new auto mode (don't fall back to search) -- args.sitelink = wikidata sitelink (if available) -- args.sisterDbName = DB name of sister site (to get sitelink) -- args.qid = QID of entity (for debugging) -- args.search = fallback string to search for -- args.logo = filename of sister logo (no namespace) -- args.sisterPrefix = wikitext prefix for sister site -- args.information = type of info sister site contains -- args.sisterName = friendly human name of sister site local function oneSister(container,args) local link = p._sisterLink(args) if not link then return nil end local li = container and container:tag('li') or mw.html.create('li') li:css("min-height","31px") -- html element for 27px-high logo local logo = li:tag('span') logo:css("display","inline-block") logo:css("width","31px") logo:css("line-height","31px") logo:css("vertical-align","middle") logo:css("text-align","center") logo:wikitext("[[File:"..args.logo.."|27x27px|middle|link=|alt=]]") -- html element for link local linkspan = li:tag('span') linkspan:css("display","inline-block") linkspan:css("margin-left","4px") linkspan:css("width","182px") linkspan:css("vertical-align","middle") linkspan:wikitext(link) return li end -- Function to create html containers for sister project link list -- Arguments: -- args = table of arguments -- args.position: if 'left', position links to left -- args.collapsible: if non-empty, make box collapsible. If 'collapse', start box hidden -- args.style: CSS style string appended to end of default CSS -- args.display: boldface name to display local function createContainer(args) -- Outermost div (css from previous version of [[Template:Project sister links]]) local container = mw.html.create('div') container:attr("role","navigation") container:attr("aria-labelledby","sister-projects") container:addClass("metadata") container:addClass("plainlinks") container:addClass("sistersitebox") container:addClass("plainlist") if args.position and args.position:lower() == "left" then container:addClass("mbox-small-left") else container:addClass("mbox-small") end if args.collapsible then container:addClass("mw-collapsible") if args.collapsible == "collapsed" then container:addClass("mw-collapsed") end end container:css("border","1px solid #aaa") container:css("padding",0) container:css("background","#f9f9f9") container:cssText(args.style) -- Div for text header local header = container:tag('div') header:css("clear",args.collapsible and "both") header:css("padding","0.75em 0") header:css("text-align","center") -- pagename in bold as part of header local pagename = header:tag('b') pagename:css("display","block") pagename:wikitext(args.display or args[1]) local headerText = "at Wikipedia's [[Wikipedia:Wikimedia sister projects|" headerText = headerText..'<span id="sister-projects">sister projects</span>]]' header:wikitext(headerText) -- start the unordered list element here local ul = container:tag('ul') ul:addClass(args.collapsible and "mw-collapsible-content") ul:css("border-top","1px solid #aaa") ul:css("padding","0.75em 0") ul:css("width","217px") ul:css("margin","0 auto") -- pass ul element back to main, so sister links can be added return ul end function p._main(args) local titleObject = mw.title.getCurrentTitle() -- Default title/search string is PAGENAME args[1] = args[1] or titleObject.text -- Canonicalize all sister links (handle yes/no/empty) for _, k in pairs({"wikt","c","commons","n","q","s","b","voy", "v","d","species","species_author","m","mw"}) do args[k] = canonicalize(args[k]) end -- Canonicalize general parameters for _,k in pairs({"auto","commonscat","author"}) do args[k] = canonicalize(args[k])[2] end -- Fill in args.qid with current qid (if available) args.qid = args.qid or mw.wikibase.getEntityIdForCurrentPage() args.qid = args.qid and args.qid:upper() -- Initialize tracking categories to "no track" wdMismatch = nil wdNamespace = nil wdHidden = nil defaultSearch = nil local ul = createContainer(args) -- WIKTIONARY oneSister(ul,{args.wikt,auto=args.auto,qid=args.qid,default=true, logo="Wiktionary-logo-v2.svg",sisterPrefix="wikt", search="Search/"..args[1],information="Definitions", sisterName="Wiktionary",sisterDbName="enwiktionary"}) -- COMMONS -- use [[Module:Commons link]] to determine best commons link local cLink = (not args.commonscat) and commonsLink._hasGallery(args.qid) or commonsLink._hasCategory(args.qid) local commonsPage = mergeArgs({args.c,args.commons}) if commonsPage[1] and not mw.ustring.match(commonsPage[1]:lower(),"^category:") then commonsPage[1] = (args.commonscat and "Category:" or "")..commonsPage[1] end local commonsSearch = "Search/"..(args.commonscat and "Category:" or "")..args[1] oneSister(ul,{commonsPage,auto=args.auto,qid=args.qid, default=true,sitelink=cLink,logo="Commons-logo.svg", sisterPrefix="c",search=commonsSearch,information="Media", sisterName="Wikimedia Commons"}) -- WIKINEWS oneSister(ul,{args.n,auto=args.auto,qid=args.qid,default=true, logo="Wikinews-logo.svg",sisterPrefix="n",search="Search/"..args[1], information="News",sisterName="Wikinews",sisterDbName="enwikinews"}) -- WIKIQUOTE oneSister(ul,{args.q,auto=args.auto,qid=args.qid,default=true, logo="Wikiquote-logo.svg",sisterPrefix="q",search="Search/"..args[1], information="Quotations",sisterName="Wikiquote",sisterDbName="enwikiquote"}) -- WIKISOURCE if args.author and args.s[1] then args.s[1] = "Author:"..args.s[1] end oneSister(ul,{args.s,auto=args.auto,qid=args.qid,default=true, logo="Wikisource-logo.svg",sisterPrefix="s",search="Search/"..args[1], information="Texts",sisterName="Wikisource",sisterDbName="enwikisource"}) -- WIKIBOOKS oneSister(ul,{args.b,auto=args.auto,qid=args.qid,default=true, logo="Wikibooks-logo.svg",sisterPrefix="b",search="Search/"..args[1], information="Textbooks",sisterName="Wikibooks",sisterDbName="enwikibooks"}) -- WIKIVOYAGE -- Information="guide" when we can be assured that search cannot be called local voyInfo = (args.voy[1] or args.voy[2] == nil) and "guide" or "information" oneSister(ul,{args.voy,auto=args.auto,qid=args.qid,default=args.auto, logo="Wikivoyage-Logo-v3-icon.svg",sisterPrefix="voy",search="Search/"..args[1], information="Travel "..voyInfo,sisterName="Wikivoyage",sisterDbName="enwikivoyage"}) -- WIKIVERSITY oneSister(ul,{args.v,auto=args.auto,qid=args.qid,default=true, logo="Wikiversity logo 2017.svg",sisterPrefix="v",search="Search/"..args[1], information="Resources",sisterName="Wikiversity",sisterDbName="enwikiversity"}) -- WIKIDATA oneSister(ul,{args.d,qid=args.qid,default=false,logo="Wikidata-logo.svg",sisterPrefix="d", sitelink=args.qid,search="ItemByTitle/enwiki/"..args[1],information="Data",sisterName="Wikidata"}) -- WIKISPECIES oneSister(ul,{mergeArgs({args.species,args.species_author},1),auto=args.auto, qid=args.qid,default=args.auto,logo="Wikispecies-logo.svg", sisterPrefix="species",search="Search/"..args[1], information=(args.species[2] and "Taxonomy") or (args.species_author[2] and "Species author") or "Taxonomy", sisterName="Wikispecies",sisterDbName="specieswiki"}) if args.species[2] and args.species_author[1] then -- If species_author is explicitly defined, and species is used, then make second row oneSister(ul,{args.species_author,auto=args.auto,qid=args.qid, default=args.auto,logo="Wikispecies-logo.svg", sisterPrefix="species",search="Search/"..args[1], information="Species author",sisterName="Wikispecies"}) end -- META oneSister(ul,{args.m,qid=args.qid,default=false,logo="Wikimedia Community Logo.svg", sisterPrefix="m",search="Search/"..args[1],information="Discussion",sisterName="Meta-Wiki"}) -- MEDIAWIKI oneSister(ul,{args.mw,qid=args.qid,default=false,logo="MediaWiki-2020-icon.svg", sisterPrefix="mw",search="Search/"..args[1],information="Documentation",sisterName="MediaWiki"}) local container = ul:allDone() -- Append tracking categories to container div -- Alpha ordering is by sister prefix if titleObject.namespace == 0 then local trackingCats = wdMismatch and "[[Category:Pages using Sister project links with wikidata mismatch|"..wdMismatch.."]]" or "" trackingCats = trackingCats..(wdNamespace and "[[Category:Pages using Sister project links with wikidata namespace mismatch|"..wdNamespace.."]]" or "") trackingCats = trackingCats..(wdHidden and "[[Category:Pages using Sister project links with hidden wikidata|"..wdHidden.."]]" or "") trackingCats = trackingCats..(defaultSearch and "[[Category:Pages using Sister project links with default search|"..defaultSearch.."]]" or "") container:wikitext(trackingCats) end return container end -- Main entry point for generating sister project links box function p.main(frame) local args = getArgs(frame,{frameOnly=false,parentOnly=false,parentFirst=false}) return tostring(p._main(args)) end -- Entry point for generating one sister link function p.link(frame) local args = getArgs(frame,{frameOnly=false,parentOnly=false,parentFirst=false}) args[1] = canonicalize(args[1]) args.auto = canonicalize(args.auto)[2] return p._sisterLink(args) end return p