Jump to content

Module:Box-header

Permanently protected module
From Wikipedia, the free encyclopedia

localgetArgs=require('Module:Arguments').getArgslocalp={}---------- Config data ----------localnamedColours=mw.loadData('Module:Box-header/colours')localmodes={lightest={sat=0.10,val=1.00},light={sat=0.15,val=0.95},normal={sat=0.40,val=0.85},dark={sat=0.90,val=0.70},darkest={sat=1.00,val=0.45},content={sat=0.04,val=1.00},grey={sat=0.00}}localmin_contrast_ratio_normal_text=7-- i.e 7:1localmin_contrast_ratio_large_text=4.5-- i.e. 4.5:1-- Template parameter aliases-- Specify each as either a single value, or a table of values-- Aliases are checked left-to-right, i.e. `['one'] = { 'two', 'three' }` is equivalent to using `{{{one| {{{two| {{{three|}}} }}} }}}` in a templatelocalparameterAliases={['1']=1,['2']=2,['colour']='color'}---------- Dependecies ----------localcolourContrastModule=require('Module:Color contrast')localhex=require('luabit.hex')---------- Utility functions ----------localfunctiongetParam(args,parameter)ifargs[parameter]thenreturnargs[parameter]endlocalaliases=parameterAliases[parameter]ifnotaliasesthenreturnnilendiftype(aliases)~='table'thenreturnargs[aliases]endfor_,aliasinipairs(aliases)doifargs[alias]thenreturnargs[alias]endendreturnnilendlocalfunctionsetCleanArgs(argsTable)localcleanArgs={}forkey,valinpairs(argsTable)doiftype(val)=='string'thenval=val:match('^%s*(.-)%s*$')ifval~=''thencleanArgs[key]=valendelsecleanArgs[key]=valendendreturncleanArgsend-- Merge two tables into a new table. If the are any duplicate keys, the values from the second overwrite the values from the first.localfunctionmergeTables(first,second)localmerged={}forkey,valinpairs(first)domerged[key]=valendforkey,valinpairs(second)domerged[key]=valendreturnmergedendlocalfunctiontoOpenTagString(selfClosedHtmlObject)localclosedTagString=tostring(selfClosedHtmlObject)localopenTagString=mw.ustring.gsub(closedTagString,' />$','>')returnopenTagStringendlocalfunctionnormaliseHexTriplet(hexString)ifnothexStringthenreturnnilendlocalhexComponent=mw.ustring.match(hexString,'^#(%x%x%x)$')ormw.ustring.match(hexString,'^#(%x%x%x%x%x%x)$')ifhexComponentand#hexComponent==6thenreturnmw.ustring.upper(hexString)endifhexComponentand#hexComponent==3thenlocalr=mw.ustring.rep(mw.ustring.sub(hexComponent,1,1),2)localg=mw.ustring.rep(mw.ustring.sub(hexComponent,2,2),2)localb=mw.ustring.rep(mw.ustring.sub(hexComponent,3,3),2)return'#'..mw.ustring.upper(r..g..b)endreturnnilend---------- Conversions ----------localfunctiondecimalToPaddedHex(number)localprefixedHex=hex.to_hex(tonumber(number))-- prefixed with '0x'localpadding=#prefixedHex==3and'0'or''returnmw.ustring.gsub(prefixedHex,'0x',padding)endlocalfunctionhexToDecimal(hexNumber)returntonumber(hexNumber,16)endlocalfunctionRGBtoHexTriplet(R,G,B)return'#'..decimalToPaddedHex(R)..decimalToPaddedHex(G)..decimalToPaddedHex(B)endlocalfunctionhexTripletToRGB(hexTriplet)localR_hex,G_hex,B_hex=string.match(hexTriplet,'(%x%x)(%x%x)(%x%x)')returnhexToDecimal(R_hex),hexToDecimal(G_hex),hexToDecimal(B_hex)endlocalfunctionHSVtoRGB(H,S,V)-- per [[HSL and HSV#Converting_to_RGB]]localC=V*SlocalH_prime=H/60localX=C*(1-math.abs(math.fmod(H_prime,2)-1))localR1,G1,B1ifH_prime<=1thenR1=CG1=XB1=0elseifH_prime<=2thenR1=XG1=CB1=0elseifH_prime<=3thenR1=0G1=CB1=XelseifH_prime<=4thenR1=0G1=XB1=CelseifH_prime<=5thenR1=XG1=0B1=CelseifH_prime<=6thenR1=CG1=0B1=Xendlocalm=V-ClocalR=R1+mlocalG=G1+mlocalB=B1+mlocalR_255=math.floor(R*255)localG_255=math.floor(G*255)localB_255=math.floor(B*255)returnR_255,G_255,B_255endlocalfunctionRGBtoHue(R_255,G_255,B_255)-- per [[HSL and HSV#Hue and chroma]]localR=R_255/255localG=G_255/255localB=B_255/255localM=math.max(R,G,B)localm=math.min(R,G,B)localC=M-mlocalH_primeifC==0thenreturnnullelseifM==RthenH_prime=math.fmod(((G-B)/C+6),6)-- adding six before taking mod ensures positive valueelseifM==GthenH_prime=(B-R)/C+2elseifM==BthenH_prime=(R-G)/C+4endlocalH=60*H_primereturnHendlocalfunctionnameToHexTriplet(name)ifnotnamethenreturnnilendlocalcodename=mw.ustring.gsub(mw.ustring.lower(name),' ','')returnnamedColours[codename]end---------- Choose colours ----------localfunctioncalculateColours(H,S,V,minContrast)localbgColour=RGBtoHexTriplet(HSVtoRGB(H,S,V))localtextColour=colourContrastModule._greatercontrast({bgColour})localcontrast=colourContrastModule._ratio({bgColour,textColour})ifcontrast>=minContrastthenreturnbgColour,textColourelseiftextColour=='#FFFFFF'then-- make the background darker and slightly increase the saturationreturncalculateColours(H,math.min(1,S+0.005),math.max(0,V-0.03),minContrast)else-- make the background lighter and slightly decrease the saturationreturncalculateColours(H,math.max(0,S-0.005),math.min(1,V+0.03),minContrast)endendlocalfunctionmakeColours(hue,modeName)localmode=modes[modeName]localisGrey=not(hue)ifisGreythenhue=0endlocalborderSat=isGreyandmodes.grey.sator0.15localborder=RGBtoHexTriplet(HSVtoRGB(hue,borderSat,0.75))localtitleSat=isGreyandmodes.grey.satormode.satlocaltitleBackground,titleForeground=calculateColours(hue,titleSat,mode.val,min_contrast_ratio_large_text)localcontentSat=isGreyandmodes.grey.satormodes.content.satlocalcontentBackground,contentForeground=calculateColours(hue,contentSat,modes.content.val,min_contrast_ratio_normal_text)returnborder,titleForeground,titleBackground,contentForeground,contentBackgroundendlocalfunctionfindHue(colour)localcolourAsNumber=tonumber(colour)ifcolourAsNumberand(-1<colourAsNumber)and(colourAsNumber<360)thenreturncolourAsNumberendlocalcolourAsHexTriplet=normaliseHexTriplet(colour)ornameToHexTriplet(colour)ifcolourAsHexTripletthenreturnRGBtoHue(hexTripletToRGB(colourAsHexTriplet))endreturnnullendlocalfunctionnormaliseMode(mode)ifnotmodeornotmodes[mw.ustring.lower(mode)]ormw.ustring.lower(mode)=='grey'thenreturn'normal'endreturnmw.ustring.lower(mode)end---------- Build output ----------localfunctionboxHeaderOuter(args)localbaseStyle={clear='both',['box-sizing']='border-box',border=(getParam(args,'border-type')or'solid')..' '..(getParam(args,'titleborder')orgetParam(args,'border')or'#ababab'),background=getParam(args,'titlebackground')or'#bcbcbc',color=getParam(args,'titleforeground')or'#000',padding=getParam(args,'padding')or'.1em',['text-align']=getParam(args,'title-align')or'center',['font-family']=getParam(args,'font-family')or'sans-serif',['font-size']=getParam(args,'titlefont-size')or'100%',['margin-bottom']='0px',}localtag=mw.html.create('div',{selfClosing=true}):addClass('box-header-title-container'):addClass('flex-columns-noflex'):css(baseStyle):css('border-width',(getParam(args,'border-top')orgetParam(args,'border-width')or'1')..'px '..(getParam(args,'border-width')or'1')..'px 0'):css('padding-top',getParam(args,'padding-top')or'.1em'):css('padding-left',getParam(args,'padding-left')or'.1em'):css('padding-right',getParam(args,'padding-right')or'.1em'):css('padding-bottom',getParam(args,'padding-bottom')or'.1em'):css('moz-border-radius',getParam(args,'title-border-radius')or'0'):css('webkit-border-radius',getParam(args,'title-border-radius')or'0'):css('border-radius',getParam(args,'title-border-radius')or'0')returntoOpenTagString(tag)endlocalfunctionboxHeaderTopLinks(args)localstyle={float='right',['margin-bottom']='.1em',['font-size']=getParam(args,'font-size')or'80%',color=getParam(args,'titleforeground')or'#000'}localtag=mw.html.create('div',{selfClosing=true}):addClass('plainlinks noprint'):css(style)returntoOpenTagString(tag)endlocalfunctionboxHeaderEditLink(args)localpage=getParam(args,'editpage')ifnotpageorpage=='{{{2}}}'thenreturn''endlocalstyle={color=getParam(args,'titleforeground')or'#000'}localtag=mw.html.create('span'):css(style):wikitext('edit')locallinktext=tostring(tag)locallinktarget=tostring(mw.uri.fullUrl(page,{action='edit',section=getParam(args,'section')}))return'['..linktarget..' '..linktext..']&nbsp;'endlocalfunctionboxHeaderViewLink(args)localstyle={color=getParam(args,'titleforeground')or'#000'}localtag=mw.html.create('span'):css(style):wikitext('view')locallinktext=tostring(tag)locallinktarget=':'..getParam(args,'viewpage')return"<b>·</b>&nbsp;[["..linktarget..'|'..linktext..']]&nbsp;'endlocalfunctionboxHeaderTitle(args)localbaseStyle={['font-family']=getParam(args,'title-font-family')or'sans-serif',['font-size']=getParam(args,'title-font-size')or'100%',['font-weight']=getParam(args,'title-font-weight')or'bold',border='none',margin='0',padding='0',color=getParam(args,'titleforeground')or'#000';}localtagName=getParam(args,'SPAN')and'span'or'h2'localtag=mw.html.create(tagName):css(baseStyle):css('padding-bottom','.1em'):wikitext(getParam(args,'title'))ifgetParam(args,'extra')thenlocalrules=mw.text.split(getParam(args,'extra'),';',true)for_,ruleinpairs(rules)dolocalparts=mw.text.split(rule,':',true)localprop=parts[1]localval=parts[2]ifpropandvalthentag:css(prop,val)endendendreturntostring(tag)endlocalfunctionboxBody(args)localbaseStyle={['box-sizing']='border-box',border=(getParam(args,'border-width')or'1')..'px solid '..(getParam(args,'border')or'#ababab'),['vertical-align']='top';background=getParam(args,'background')or'#fefeef',opacity=getParam(args,'background-opacity')or'1',color=getParam(args,'foreground')or'#000',['text-align']=getParam(args,'text-align')or'left',margin='0 0 10px',padding=getParam(args,'padding')or'1em',}localtag=mw.html.create('div',{selfClosing=true}):css(baseStyle):css('border-top-width',(getParam(args,'border-top')or'1')..'px'):css('padding-top',getParam(args,'padding-top')or'.3em'):css('border-radius',getParam(args,'border-radius')or'0')returntoOpenTagString(tag)endlocalfunctioncontrastCategories(args)localcats=''localtitleText=nameToHexTriplet(getParam(args,'titleforeground'))ornormaliseHexTriplet(getParam(args,'titleforeground'))or'#000000'localtitleBackground=nameToHexTriplet(getParam(args,'titlebackground'))ornormaliseHexTriplet(getParam(args,'titlebackground'))or'#bcbcbc'localtitleContrast=colourContrastModule._ratio({titleBackground,titleText})localinsufficientTitleContrast=type(titleContrast)=='number'and(titleContrast<min_contrast_ratio_large_text)localbodyText=nameToHexTriplet(getParam(args,'foreground'))ornormaliseHexTriplet(getParam(args,'foreground'))or'#000000'localbodyBackground=nameToHexTriplet(getParam(args,'background'))ornormaliseHexTriplet(getParam(args,'background'))or'#fefeef'localbodyContrast=colourContrastModule._ratio({bodyBackground,bodyText})localinsufficientBodyContrast=type(bodyContrast)=='number'and(bodyContrast<min_contrast_ratio_normal_text)ifinsufficientTitleContrastandinsufficientBodyContrastthenreturn'[[Category:Box-header with insufficient title contrast]][[Category:Box-header with insufficient body contrast]]'elseifinsufficientTitleContrastthenreturn'[[Category:Box-header with insufficient title contrast]]'elseifinsufficientBodyContrastthenreturn'[[Category:Box-header with insufficient body contrast]]'elsereturn''endend---------- Main functions / entry points ------------ Entry point for templates (manually-specified colours)functionp.boxHeader(frame)localargs=getArgs(frame)localpage=args.editpageifnotargs.editpageorargs.editpage==''thenpage=mw.title.getCurrentTitle().prefixedTextendlocaloutput=p._boxHeader(args,page)ifmw.ustring.find(output,'{')thenreturnframe:preprocess(output)endreturnoutputend-- Entry point for modules (manually-specified colours)functionp._boxHeader(_args,page)localargs=setCleanArgs(_args)ifpageandnotargs.editpagethenargs.editpage=pageendifnotargs.titlethenargs.title='{{{title}}}'endlocaloutput={}table.insert(output,boxHeaderOuter(args))ifnotgetParam(args,'EDITLINK')thentable.insert(output,boxHeaderTopLinks(args))ifnotgetParam(args,'noedit')thentable.insert(output,boxHeaderEditLink(args))endifgetParam(args,'viewpage')thentable.insert(output,boxHeaderViewLink(args))endifgetParam(args,'top')thentable.insert(output,getParam(args,'top')..'&nbsp;')endtable.insert(output,'</div>')endtable.insert(output,boxHeaderTitle(args))table.insert(output,'</div>')table.insert(output,boxBody(args))ifnotgetParam(args,'TOC')thentable.insert(output,'__NOTOC__')endifnotgetParam(args,'EDIT')thentable.insert(output,'__NOEDITSECTION__')endtable.insert(output,contrastCategories(args))returntable.concat(output)end-- Entry point for templates (automatically calculated colours)functionp.autoColour(frame)localargs=getArgs(frame)localcolourParam=getParam(args,'colour')localgeneratedColour=nilifnotcolourParamorcolourParam==''then-- convert the root page name into a number and use thatlocalroot=mw.title.getCurrentTitle().rootPageTitle.prefixedTextlocalrootStart=mw.ustring.sub(root,1,12)localdigitsFromRootStart=mw.ustring.gsub(rootStart,".",function(s)returnmath.fmod(string.byte(s,2)orstring.byte(s,1),10)end)localnumberFromRoot=tonumber(digitsFromRootStart,10)generatedColour=math.fmod(numberFromRoot,360)endlocaloutput=p._autoColour(args,generatedColour)ifmw.ustring.find(output,'{')thenreturnframe:preprocess(output)endreturnoutputend-- Entry point for modules (automatically calculated colours)functionp._autoColour(_args,generatedColour)localargs=setCleanArgs(_args)localhue=generatedColourorfindHue(getParam(args,'colour'))localmode=normaliseMode(getParam(args,'mode'))localborder,titleForeground,titleBackground,contentForeground,contentBackground=makeColours(hue,mode)localboxTemplateArgs=mergeTables(args,{title=getParam(args,'1')or'{{{1}}}',editpage=getParam(args,'2')or'',noedit=getParam(args,'2')and''or'yes',border=border,titleforeground=titleForeground,titlebackground=titleBackground,foreground=contentForeground,background=contentBackground})returnp._boxHeader(boxTemplateArgs)endreturnp
close