Module:Sister project links

-- 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.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("") -- 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 "	headerText = headerText..' sister projects ' 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-logo.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 "" or "" trackingCats = trackingCats..(wdNamespace and "" or "") trackingCats = trackingCats..(wdHidden and "" or "") trackingCats = trackingCats..(defaultSearch and "" 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