diff --git a/lua/spec/league_icon_spec.lua b/lua/spec/league_icon_spec.lua index 455700d019a..e733b1c9c69 100644 --- a/lua/spec/league_icon_spec.lua +++ b/lua/spec/league_icon_spec.lua @@ -2,17 +2,27 @@ local LeagueIcon = require('Module:LeagueIcon') local FILLER_EXPECT = '[[File:Logo filler event.png|link=]]' -local ICON_DARK_EXPECT = '[[File:DarkIcon.png|link=||50x50px]]' +local ICON_DARK_EXPECT = '[[File:DarkIcon.png|link=|50x50px]]' local ICON_BOTH_EXPECT = - '[[File:LightIcon.png|link=||50x50px]]' .. - '[[File:DarkIcon.png|link=||50x50px]]' + '[[File:LightIcon.png|link=|50x50px]]' .. + '[[File:DarkIcon.png|link=|50x50px]]' local ICON_WITH_LINK_EXPECT = '[[File:Icon.png|link=link|name|50x50px]]' local ICON_WITH_LINK_BOTH_EXPECT = '[[File:LightIcon.png|link=link|name|50x50px]]' .. '[[File:DarkIcon.png|link=link|name|50x50px]]' insulate('LeagueIcon.display', function() + local AddCategorySpy + + before_each(function() + AddCategorySpy = spy.on(mw.ext.TeamLiquidIntegration, 'add_category') + end) + + after_each(function() + AddCategorySpy:revert() + end) + it('should return filler icon when no icons are provided', function() local args = {} local result = LeagueIcon.display(args) @@ -22,25 +32,29 @@ insulate('LeagueIcon.display', function() it('should return iconDark when only iconDark is provided', function() local args = {iconDark = 'DarkIcon.png'} local result = LeagueIcon.display(args) - assert.are.equal(ICON_DARK_EXPECT .. '[[Category:Pages with only icondark]]', result) + assert.are.equal(ICON_DARK_EXPECT, result) + assert.stub(AddCategorySpy).was.called_with('Pages with only icondark') end) it('should return both icons when both icon and iconDark are provided', function() local args = {icon = 'LightIcon.png', iconDark = 'DarkIcon.png'} local result = LeagueIcon.display(args) assert.are.equal(ICON_BOTH_EXPECT, result) + assert.stub(AddCategorySpy).was.called_at_most(0) end) it('should not use template when noTemplate option is true', function() local args = {options = {noTemplate = true}} local result = LeagueIcon.display(args) assert.are.equal(FILLER_EXPECT, result) + assert.stub(AddCategorySpy).was.called_at_most(0) end) it('should not include link when noLink option is true', function() local args = {icon = 'LightIcon.png', iconDark = 'DarkIcon.png', options = {noLink = true}} local result = LeagueIcon.display(args) assert.are.equal(ICON_BOTH_EXPECT, result) + assert.stub(AddCategorySpy).was.called_at_most(0) end) end) @@ -109,7 +123,7 @@ end) insulate('LeagueIcon.generate', function() it('should generate code with valid arguments', function() local args = {icon = 'Icon.png', link = 'link', name = 'name', series = 'series'} - GoldenTest('LeagueIcon.generate_copy_paste_gen', LeagueIcon.generate(args)) + GoldenTest('LeagueIcon.generate_copy_paste_gen', tostring(LeagueIcon.generate(args))) end) it('should throw error when no link or series is provided', function() diff --git a/lua/wikis/commons/LeagueIcon.lua b/lua/wikis/commons/LeagueIcon.lua index c577c240791..751a5812701 100644 --- a/lua/wikis/commons/LeagueIcon.lua +++ b/lua/wikis/commons/LeagueIcon.lua @@ -8,13 +8,18 @@ local Lua = require('Module:Lua') local LeagueIcon = {} +local Array = Lua.import('Module:Array') local Class = Lua.import('Module:Class') local Template = Lua.import('Module:Template') local Logic = Lua.import('Module:Logic') local String = Lua.import('Module:StringUtils') -local FILLER = '[[File:Logo filler event.png|link=]]' -local NO_ICON_BUT_ICONDARK_TRACKING_CATEGORY = '[[Category:Pages with only icondark]]' +local Html = Lua.import('Module:Widget/Html') +local Link = Lua.import('Module:Widget/Basic/Link') +local WidgetUtil = Lua.import('Module:Widget/Util') + +local FILLER_IMAGE = 'Logo filler event.png' +local NO_ICON_BUT_ICONDARK_TRACKING_CATEGORY = 'Pages with only icondark' ---@class LeagueIconDisplayArgs ---@field icon string? @@ -42,21 +47,21 @@ function LeagueIcon.display(args) local icon = args.icon local trackingCategory = '' if not Logic.readBool(options.noTemplate) and String.isEmpty(icon) and String.isEmpty(iconDark) then - local stringOfExpandedTemplate = LeagueIcon.getTemplate({ + local stringOfExpandedTemplate = LeagueIcon.getTemplate{ series = args.series, abbreviation = args.abbreviation, date = args.date - }) - icon, iconDark, trackingCategory = LeagueIcon.getIconFromTemplate({ + } + icon, iconDark, trackingCategory = LeagueIcon.getIconFromTemplate{ icon = icon, iconDark = iconDark, stringOfExpandedTemplate = stringOfExpandedTemplate - }) + } end --if icon and iconDark are not given and can not be retrieved return filler icon if String.isEmpty(icon) and String.isEmpty(iconDark) then - return FILLER + return tostring(LeagueIcon._generateWikiCode(FILLER_IMAGE, '')) end if String.isEmpty(icon) then @@ -76,9 +81,13 @@ function LeagueIcon.display(args) else link = args.link or args.series or args.abbreviation or args.name or '' end - return LeagueIcon._make(icon, iconDark, link, args.name, size) .. trackingCategory + if String.isNotEmpty(trackingCategory) then + mw.ext.TeamLiquidIntegration.add_category(trackingCategory) + end + return LeagueIcon._make(icon, iconDark, link, args.name, size) end +---@private ---@param icon string ---@param iconDark string ---@param link string @@ -91,23 +100,38 @@ function LeagueIcon._make(icon, iconDark, link, name, size) icon = string.gsub(icon, '^File:', '') iconDark = string.gsub(iconDark, '^File:', '') - local imageOptions = '|link=' .. link .. '|' .. (name or link) .. '|' .. size .. 'x' .. size .. 'px]]' - if icon == iconDark then - return tostring(mw.html.create('span') - :addClass('league-icon-small-image') - :wikitext('[[File:' .. icon .. imageOptions)) + return tostring(LeagueIcon._generateWikiCode(icon, link, name, size)) end - local lightSpan = mw.html.create('span') - :addClass('league-icon-small-image lightmode') - :wikitext('[[File:' .. icon .. imageOptions) - local darkSpan = mw.html.create('span') - :addClass('league-icon-small-image darkmode') - :wikitext('[[File:' .. iconDark .. imageOptions) + local lightSpan = LeagueIcon._generateWikiCode(icon, link, name, size, 'lightmode') + local darkSpan = LeagueIcon._generateWikiCode(iconDark, link, name, size, 'darkmode') return tostring(lightSpan) .. tostring(darkSpan) end +---@private +---@param icon string +---@param link string +---@param name string? +---@param size number? +---@param additionalClasses string|string[]? +---@return HtmlNode +function LeagueIcon._generateWikiCode(icon, link, name, size, additionalClasses) + return Html.Span{ + classes = Array.extend('league-icon-small-image', additionalClasses), + children = { + '[[', + table.concat(Array.extend( + 'File:' .. icon, + 'link=' .. link, + Logic.emptyOr(name, link), + size and (size .. 'x' .. size .. 'px') or nil + ), '|'), + ']]' + } + } +end + ---Retrieve icon and iconDark from LeagueIconSmall templates ---@param args {icon: string?, iconDark: string?, stringOfExpandedTemplate: string?} ---@return string, string, string @@ -190,48 +214,52 @@ end --generate copy paste code for new LeagueIconSmall templates --to be used with a form ---@param args LeagueIconGenerateArgs ----@return string +---@return Renderable function LeagueIcon.generate(args) local link = args.link or args.series - if String.isEmpty(link) then - error('No series/link specified') - end + assert(String.isNotEmpty(link), 'No series/link specified') + ---@cast link -nil local name = args.name or link local icon = args.icon - if String.isEmpty(icon) then - error('No icon file specified') - end - local iconDark = args.iconDark or icon - - local imageOptions = '|link={{{1|{{{link|' .. link .. '}}}}}}|{{{name|{{{1|{{{link|' .. name .. '}}}}}}}}}|50x50px]]' + assert(String.isNotEmpty(icon), 'No icon file specified') + + return Html.Fragment{children = WidgetUtil.collect( + Html.Pre{ + classes = {'selectall'}, + children = {mw.text.nowiki(LeagueIcon._generateTemplateCode(icon, args.iconDark, link, name))} + }, + LeagueIcon._buildLinkToTemplate(args) + )} +end - if icon == iconDark then - return '
' .. mw.text.nowiki(
-			'' ..
-			'[[File:' .. icon .. imageOptions .. '[[Category:Small League Icon Templates]]') .. '
' - .. LeagueIcon._buildLinkToTemplate(args) +---@private +---@param icon string +---@param iconDark string? +---@param link string +---@param name string +---@return string +function LeagueIcon._generateTemplateCode(icon, iconDark, link, name) + local linkOption = '{{{1|{{{link|' .. link .. '}}}}}}' + local nameOption = '{{{name|{{{1|{{{link|' .. name .. '}}}}}}}}}' + if String.isEmpty(iconDark) or icon == iconDark then + return tostring(LeagueIcon._generateWikiCode(icon, linkOption, nameOption, 50)) + .. '[[Category:Small League Icon Templates]]' end - - return '
' .. mw.text.nowiki(
-		'' ..
-		'[[File:' .. icon .. imageOptions .. '' ..
-		'[[File:' .. iconDark .. imageOptions .. '[[Category:Small League Icon Templates]]') .. '
' - .. LeagueIcon._buildLinkToTemplate(args) + ---@cast iconDark -nil + return tostring(LeagueIcon._generateWikiCode(icon, linkOption, nameOption, 50, 'lightmode')) + .. '' + .. tostring(LeagueIcon._generateWikiCode(iconDark, linkOption, nameOption, 50, 'darkmode')) + .. '[[Category:Small League Icon Templates]]' end --generate copy paste code for new historical LeagueIconSmall templates --to be used with a form ---@param args table ----@return string +---@return HtmlNode function LeagueIcon.generateHistorical(args) local title = args.title or args.series - if String.isEmpty(title) then - error('No template title specified') - end + assert(String.isNotEmpty(title), 'No template title specified') local link = args.link or title local name = args.name or link local timeName = title:lower() .. 'time' @@ -272,20 +300,31 @@ function LeagueIcon.generateHistorical(args) end comparisons = '-->{{#ifexpr:' .. comparisons - return '
' .. mw.text.nowiki(
-			defineTime .. comparisons .. '-->[[Category:Historical Small League Icon template]]'
-		) .. '
' .. LeagueIcon._buildLinkToTemplate(args) + return Html.Fragment{children = WidgetUtil.collect( + Html.Pre{ + classes = {'selectall'}, + children = {mw.text.nowiki( + defineTime .. comparisons .. '-->[[Category:Historical Small League Icon template]]' + )} + }, + LeagueIcon._buildLinkToTemplate(args) + )} end +---@private ---@param args {templateName: string?, wiki: string?} ----@return string +---@return Renderable[]? function LeagueIcon._buildLinkToTemplate(args) if String.isEmpty(args.templateName) or String.isEmpty(args.wiki) then - return '' + return end - return '
Link to the template page: [[' .. args.wiki .. - ':Template:LeagueIconSmall/' .. args.templateName:lower() .. ']]' + return { + Html.Br{}, + Html.B{children = {'Link to the template page:'}}, + ' ', + Link{link = args.wiki .. ':Template:LeagueIconSmall/' .. args.templateName:lower()} + } end return Class.export(LeagueIcon, {frameOnly = true, exports = {