Jump to content
Toggle menu
  • 8 articles
  • 75 files
  • 7 users
  • 37.8K edits
Neodyland Wiki
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Clickable button: Difference between revisions

From Neodyland Wiki
merge
m 9 revisions imported
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- @module 'Codex clickable button'
--- @module 'CodexClickableButton'
--- Generates wikitext for clickable Codex button.
---
--- Outputs wikitext to render the (button component)[mdoc:codex/latest/components/demos/button.html]
--- from the (Codex design system for Wikimedia)[https://doc.wikimedia.org/codex/latest].
---- Options to include an icon or create an icon-only button.
---- Target a URL or a wikilink
---- Set the weight, size and state of the button (enabled or disabled).
---- Dummy button creation can be disabled.
---
--- Includes helper functions for URL parsing and cleaning, and adding tracking
--- categories. Intended for use in templates and other modules.
--- Supports legacy parameters. To add icons, see CSS link in constants below.
---
--- @author [[User:Waddie96]]
--- @author [[User:Waddie96]]
--- -@see [[en:Module:Clickable_button]]
--- @license CC-BY-SA-4.0/GFDL
--- @license CC-BY-SA-4.0/GFDL
--- @class CodexClickableButton extends ClickableButton
---  Table containing arguments for the button.
--- @class args table
--- @class args table
--- @field label string
--- @field label? string The button's visible text label.
--- Generates wikitext for clickable Codex button.
--- @field link? string|'no' The target wikilink for the button.
--- Generates wikitext to render the button component from the (Codex design
--- @field url? string The target external URL for the button.
--- system for Wikimedia)[https://doc.wikimedia.org/codex/latest].
--- @field icon? string The name of the icon to display found in CSS file.
--- - Options to include an icon
--- @field color? 'blue'|'green'|'red'|string Legacy color parameter.
--- - Create an icon-only or a dummy button
--- @field class? string Custom CSS classes for the button.
--- - Target a URL or a wikilink
--- @field weight? 'quiet'|'normal'|'primary' The visual weight of the button.
--- - Set the weight, size and state of the button (enabled or disabled).
--- @field size? 'small'|'medium'|'large' The size of the button.
--- Includes helper functions for URL parsing and cleaning, adding tracking  
--- @field action? 'progressive'|'destructive'|'default'|string The action type of the button.
--- categories. Intended for use in templates and other modules.
--- @field disabled? boolean|'1'|string Whether the button is disabled/greyed out. `disabled` is `true` if: `link` = `'no'` or `false` or `disabled` = `'1'` or `true`.
--- Implements [[Template:Clickable button]] and others.
--- @field style? string Custom inline CSS styles.
--- Supports legacy parameters.
--- @field nocat? boolean|string If `true`, suppresses tracking categories.
--- To add icons: [[Template:Clickable button/styles.css]].
--- @field category? string An additional category to add.
 
--- @field aria-label? string The ARIA label for accessibility.
-- TRACKING CATEGORIES:
--- @field arialabel? string (alias for aria-label)
-- [[Category:Pages using clickable dummy button]]
--- @field aria_label? string (alias for aria-label)
-- [[Category:Pages using disabled button]]
--- @field [1]? string Positional argument 1 (alias for link/label).
-- [[Category:Pages using clickable button with external links]]
--- @field [2]? string Positional argument 2 (alias for label).
-- [[Category:Pages using clickable button with outdated classes]]
--- @var categories? string|boolean Additional categories to add.
-- [[Category:Errors reported by Module:Clickable button]]
--- @var ariaDisabled? boolean Internal flag indicating if the button is functionally disabled for ARIA.
-- unless nocat=true. Adds category= any custom category regardless of nocat=.
--- @var oldClassMatched string|boolean Internal flag for outdated classes.
--- @var isUrl boolean Whether the link is a URL.
--- @var errorText string|nil
--- @var tblClasses table Classes for the button span tag.
--- @var pageTitle mw.title Title of the current page.
--- @todo [[Module:Neturl]] [[Module:Check for unknown parameters]]


-- DEPENDENCIES:
----require('strict')
local yesno = require('Module:Yesno')
local yesno = require('Module:Yesno')
-- [[Template:Clickable button/styles.css]]
local delink = require('Module:Delink')._delink
-- [[Module:Yesno]] [[Module:Arguments]]
-- [[Module:Check for unknown parameters]]
-- [[Special:Version]] must include @wikimedia/codex.
-- [[Module:If preview]]


local p = {}
local p = {}
local gsub = mw.ustring.gsub
local len = mw.ustring.len
local lower = mw.ustring.lower
local trim = mw.text.trim
local html = mw.html


--- Creates [URI object](lua://mw.uri) from URL.
function p.main(frame)
--- Checks the URI is safe for use as a wikilink in MediaWiki.
local getArgs = require('Module:Arguments').getArgs
---@class mw.uri: string
local args = getArgs(frame)
---@param s string The URL to check.
return p._main(args)
---@return mw.uri|nil uri The URI of the given URL.
local function safeUri(s)
local success, uri = pcall(function()
return mw.uri.new(s)
end)
if success then
return uri
else
return nil
end
end
end


--- Extracts a URL from a string.
function p._main(args)
---@param extract string The full string from which the URL must be obtained.
-- If first arg or a url is not provided,
---@return string|nil url The raw URL.
-- but we have a second arg, make a button.
local function extractUrl(extract)
-- Otherwise, return nothing.
local url = extract
args.originalInput = args[1]
---@type string Extracted URL.
args[1] = delink({args[1]})
url = gsub(url, '^([Hh]?[Tt]?[Tt]?[Pp]?[Ss]?:/*)(.+)',
if args[1] == "" then
'https://%2')
args[1] = nil
---@type mw.uri|nil
local uri = safeUri(url);
if uri and uri.host then
return url
end
end
return nil
end
--- Parses the `url`. The `url` parameter is required. `text` label is
--- optional and can be generated from the `url`.
---@param url string|nil The URL
---@param text? string|nil The display label of the wikilink
---@return string|nil url The URL
---@return string|nil text The display label of the wikilink
local function _url(url, text)
---@type string URL with trailing whitespace removed
url = trim(url or '')
text = trim(text or '')


if url == '' then
if not args[1] and not args.url then
return '', text
if args[2] then
end
p.nolink = true
 
-- If the URL contains any unencoded spaces, encode them,
-- because MediaWiki will otherwise interpret a space as the end of the URL.
url = gsub(url, '%s', function(s)
return mw.uri.encode(s, 'PATH')
end)
 
-- If there is an empty query string or fragment ID,
-- remove it as it will cause mw.uri.new to throw an error
url = gsub(url, '#$', '')
url = gsub(url, '%?$', '')
-- If it's an http(s) URL without the double slash, fix it.
url = gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3')
----url = gsub(url, '^([Hh]?[Tt]?[Tt]?[Pp]?[Ss]?:/*)(.+)',
---- 'https://%2')
 
---@type mw.uri|nil
local uri = safeUri(url)
 
-- Handle URL's without a protocol or are protocol-relative.
-- e.g., www.example.com/foo or www.example.com:8080/foo, and //www.example.com/foo
if uri and (not uri.protocol or (uri.protocol and not uri.host)) and url:sub(1, 2) ~= '//' then
url = 'http://' .. url
uri = safeUri(url)
end
 
if text == '' then
if uri then
if uri.path == '/' then
uri.path = ''
end
local port = ''
if uri.port then
port = ':' .. uri.port
end
text = lower(uri.host or '') .. port .. (uri.relativePath or '')
-- Add `<wbr>` before `_/.-#` sequences
-- This entry _must_ be the first. `<wbr/>` has a `/` in it, you know.
text = gsub(text, "(/+)", "<wbr/>%1")
text = gsub(text, "(%.+)", "<wbr/>%1")
-- _Disabled_ for now.
---- text = gsub(text,"(%-+)","<wbr/>%1")
text = gsub(text, "(%#+)", "<wbr/>%1")
text = gsub(text, "(_+)", "<wbr/>%1")
else
else
-- URL is badly-formed, so just display whatever was given.
return ''
text = url
end
end
end
end


return url, text
local data = p.makeLinkData(args)
local link = p.renderLink(args.originalInput, data)
local trackingCategories = p.renderTrackingCategories(args)
return link .. trackingCategories
end
end


--- Cleans and normalises a URL string.
function p.makeLinkData(args)
--- Copied from [[en:Module:URL]] with minor modifications.
local data = {}
--- - Encodes `url`.
--- - Removes empty query strings and fragement IDs.
--- - Fixes the protocol and the double slash that follows, i.e. `https://`
--- - Handles URLs that have no protocol or are protocol-relative.
--- - Generates label from the URL if one is not given.
---@param url string The raw URL to clean.
---@param text string Optional link display text.
---@return string|nil localUrl Cleaned URL for wikilink.
---@return string|nil text Display label for wikilink.
----@deprecated `mw.uri` was deprecated in MW 1.43 in favour of the native browser `URL`.
local function url(url, text)
local localUrl = url
localUrl = localUrl or extractUrl(localUrl) or extractUrl(text) or ''
-- Strip out HTML tags and [ ] from URL
localUrl = (localUrl or ''):gsub("<[^>]*>", ""):gsub("[%[%]]", "")
-- Truncate anything after a space
localUrl = localUrl:gsub("%%20", " "):gsub(" .*", "")
return _url(localUrl, text)
end


--- Renders tracking categories based on given parameters. Also checks for unknown parameter use,
-- Get the link and display values,
--- validates given arguments, and categorizes accordingly.
-- and find whether we are outputting
---@param args table Original arguments given to module.
-- a wikilink or a URL.
local function renderTrackingCategories(args)
if args.url then
local categories = ''
data.isUrl = true
local class = args.class or ''
data.link = args.url
---- local check_for_unknown_parameters = require("Module:Check for unknown parameters")._check
if args[1] then
---- local title = mw.title.getCurrentTitle()
data.display = args[1]
--- Don't add categories if `nocat=true`, but still add any custom category.
elseif args[2] then
--- Custom category passed in
data.display = args[2]
if args.category --[[and yesno(args.nocat) == false]] then
else
local s = args.category
data.display = args.url
s = s:gsub('%[%[', ''):gsub('%]%]', ''):gsub('[Cc]ategory:', '')
p.urlisdisplay = true
categories = categories .. '[[' .. 'Category:' .. s .. ']]'
end
else
data.isUrl = false
p.urlisdisplay = false
data.link = args[1]
if args[2] then
data.display = args[2]
else
data.display = args[1]
end
if args[1] and args[1]:find('http') then
data.isUrl = true
end
end
end
if yesno(args.nocat) == true then
return categories or ''
if yesno(args.link) == false then
p.nolink = true
end
end


--[=[
-- Colours
categories = categories .. check_for_unknown_parameters({
-- For the merge with {{clickable button}}
checkpositional = "y",
local colour = args.color and args.color:lower()
ignoreblank = "y",
regexp1 = "header[%d]+",
regexp2 = "label[%d]+",
regexp3 = "data[%d]+[abc]?",
regexp4 = "class[%d]+[abc]?",
regexp5 = "rowclass[%d]+",
regexp6 = "rowstyle[%d]+",
regexp7 = "rowcellstyle[%d]+",
unknown = "[[Category:Pages using infobox3cols with undocumented parameters|_VALUE_" .. title.text .. "]]",
'class', 'color', 'weight', 'size', 'icon', 'link', 'url', 'disabled',
'label', 'aria-label', 'arialabel', 'aria_label', 'action', 'nocat',
'category', '1', '2'
}, args) ]=]


--- Dummy button is:
-- Classes
--- - Clickable (i.e. not disabled visually)
local class = args.class and args.class:lower()
--- - No target link/URL (i.e., gives feedback it'll do something,
data.classes = {}
---  but does nothing).
if class == 'ui-button-green'
--- They should all have `ariaDisabled == true`, therefore `aria-disabled = true`
if (not args.link or yesno(args.link) == false)
and not args.url
and not args.disabled then
categories = categories .. '[[Category:Pages using clickable dummy button]]'
end
--- Disabled button is:
--- - Greyed out (`args.disabled == true`)
--- - Will likely have no link/URL
if args.disabled then
categories = categories .. '[[Category:Pages using disabled button]]'
end
 
if class == 'ui-button-green'
or class == 'ui-button-blue'
or class == 'ui-button-blue'
or class == 'ui-button-red'
or class == 'ui-button-red'
or class == 'mw-ui-progressive'
then
or class == 'mw-ui-destructive' then
table.insert(
categories = categories .. '[[Category:Pages using clickable ' ..
data.classes,
'button with outdated classes]]'
'submit ui-button ui-widget ui-state-default ui-corner-all'
.. ' ui-button-text-only ui-button-text'
)
else
table.insert(data.classes, 'mw-ui-button')
end
end
if args.url then
categories = categories .. '[[Category:Pages using clickable ' ..
--If class is unset,
'button with external links]]'
--then let color determine class
if not class then
if colour == 'blue' then
class = 'mw-ui-progressive'
elseif colour == 'red' then
class = 'mw-ui-destructive'
elseif colour == 'green' then
class = 'mw-ui-constructive'
end
end
end
if class == 'mw-ui-constructive' then
categories = categories .. '[[Category:Pages using clickable ' ..
if class then
'button with deprecated parameters]]'
table.insert(data.classes, class)
end
return categories
end
 
--- Renders the wikitext span tags for the button
--- @param data table
--- @return string link
local function renderLink(data)
---@class mw.html: string MediaWiki DOM document content model based on HTML and RDFa
---@type mw.html Span tag that creates the button
local displaySpan = html.create('span')
for _, aClass in ipairs(data.classes or {}) do
displaySpan:addClass(aClass)
end
displaySpan:attr('role', 'button')
if data.aria_label then
displaySpan:attr('aria-label', data.aria_label)
end
end


if data.iconSpan then
-- Styles
displaySpan:node(data.iconSpan)
do
end
--[[
if data.label then
-- Check whether we are on the same page as we have specified in
displaySpan:wikitext(data.label)
-- args[1], but not if we are using a URL link, as then args[1] is only
end
-- a display value. If we are currently on the page specified in
 
-- args[1] make the button colour darker so that it stands out from
--- Wikilink that wraps around button wikitext
-- other buttons on the page.
---@type string
--]]
local link
local success, linkTitle, currentTitle
if data.disabled then
if not data.isUrl then
-- ARIA disabled attribute for disabled buttons
currentTitle = mw.title.getCurrentTitle()
displaySpan:attr('aria-disabled', 'true')
success, linkTitle = pcall(mw.title.new, args[1])
link = string.format('%s %s', tostring(displaySpan), data.categories)
elseif p.urlisdisplay then
elseif data.ariaDisabled then
currentTitle = mw.title.getCurrentTitle()
-- ARIA disabled attribute for no-link/dummy buttons
displaySpan:attr('aria-disabled', 'true')
link = string.format('%s %s', tostring(displaySpan), data.categories)
else
displaySpan:attr('aria-disabled', 'false')
if data.isUrl then
link = string.format('<span class="plainlinks">[%s %s]</span> %s',
data.url, tostring(displaySpan), data.categories)
elseif data.isUrl == false then
link = string.format('[[%s|%s]] %s', data.link, tostring(displaySpan),
data.categories)
else-- `data.isUrl` should be `nil` to get here.
-- Dummy/disabled button
link = string.format('%s %s', tostring(displaySpan), data.categories)
end
end
end
if success
 
and linkTitle
if data.error then
and mw.title.equals(currentTitle, linkTitle)
--- Generate error message when viewed in preview.
and not p.urlisdisplay
--- Categorise into [[Category:Errors reported by Module:Clickable button]]
then
---@class ifPreview
if class == 'ui-button-blue'
---@field main function
or class == 'mw-ui-progressive'
---@type ifPreview
or class == 'mw-ui-constructive'
local ifPreview = require('Module:If preview')
then
if yesno(data.nocat) ~= true then
data.backgroundColor = '#2962CB'
link = link .. ' ' .. '[[Category:Errors reported by Module:Clickable button]]'
data.color = '#fff'
elseif class == 'ui-button-green' then
data.backgroundColor = '#008B6D'
elseif class == 'ui-button-red' or class == 'mw-ui-destructive' then
data.backgroundColor = '#A6170F'
else
data.backgroundColor = '#CCC'
data.color = '#666'
end
elseif p.urlisdisplay then
data.dummyLink = tostring(currentTitle)
end
end
return ifPreview.main( { data.error .. link, link } )
-- Add user-specified styles.
data.style = args.style
end
end
 
return data
return link
end
end


--- Parses the module's arguments for backward compatibility with deprecated
function p.renderLink(originalInput, data)
--- parameters from old templates and modules.
-- Render the display span tag.
---@param args table Module arguments.
local display
---@return table args Parsed arguments.
do
local function parseParameters(args)
local displaySpan = mw.html.create('span')
--- It's weird that we may make a link a label, but if we truly
for i, class in ipairs(data.classes or {}) do
--- only got positional argument `1`, then that would mean it's
displaySpan:addClass(class)
--- intentional to make both the link and label the same.
end
--- `label` value priority: `label` > `2` > `1`
---@type string
args.label = args.label or args[2] or args[1]


--- `disabled` is `true` if:
displaySpan
--- - `link` = `'no'` or `false`
:css{
--- - `disabled` = `'1'` or `true`
['background-color'] = data.backgroundColor,
---@TODO Should `link == 'no'` disable dummy
color = data.color
---      buttons?
}
---@type boolean
if data.style then
args.disabled = yesno(args.disabled) or (yesno(args.link) == false)
displaySpan:cssText(data.style)
--- `link` value priority: `link` > `1`
end
---@type string
displaySpan:wikitext(data.display)
args.link = args.link or args[1]
display = tostring(displaySpan)
if args.disabled then
-- If `link` was `'no'`, i.e. `true`, then must
-- not generate a link either. Clearing after assigning
-- positional arg[1].
args.link = nil
args.url = nil
end
end


-- Remove positional args after assigning
-- Render the link
args[1] = nil
local link
args[2] = nil
if originalInput and originalInput:find('|') then
 
link = string.format('[[%s|%s]]', delink({originalInput, wikilinks = 'target'}), display)
if (args.link and yesno(args.link) ~= false) or args.url then
elseif p.nolink then
args.ariaDisabled = false
if p.urlisdisplay then
link = string.format('[[%s|%s]]', data.dummyLink, display)
else
link = string.format('%s', display)
end
else
else
--- `aria-disabled = true` if no link whatsoever, always.
if data.isUrl then
--- Make dummy button. But for accessibility,
link = string.format('[%s %s]', data.link, display)
--- ARIA must know it won't do anything.
else
--- _OPTION_ to forcefully disable dummy buttons
link = string.format('[[%s |%s]]', data.link, display)
--- by setting: `args.disabled = true`
end
args.ariaDisabled = true
end
 
-- Normalize ARIA label keys
args.aria_label = args.aria_label or args['aria-label'] or args.arialabel
 
-- Determine action from old parameters color/class
local color = type(args.color) == 'string' and args.color:lower() or ''
local class = type(args.class) == 'string' and lower(args.class) or ''
if ( color == 'blue'
or color == 'green'
or class == 'ui-button-green'
or class == 'ui-button-blue'
or class == 'mw-ui-constructive'
or class == 'mw-ui-progressive'
or class == 'progressive') then
args.action = "progressive"
args.class = nil
elseif (color == "red"
or class == 'ui-button-red'
or class == 'mw-ui-destructive'
or class == 'destructive') then
args.action = "destructive"
args.class = nil
end
end


return args
return string.format('<span class="plainlinks clickbutton">%s</span>', link)
end
end


--- Constructs the attributes for the wikitext/HTML elements.
function p.renderTrackingCategories(args)
---@param args table Parsed arguments.
if yesno(args.category) == false then
---@return table data Data, such as attributes, ready to be assembled.
return ''
local function makeLinkData(args)
local data = {}
 
-- Decide link vs. url vs. none
-- URL has priority over link if both provided.
-- Make pretty URL and label based on URL if no label.
if args.url then
data.isUrl = true
local label
data.url, label = url(args.url, args.label)
data.label = args.label or label
elseif args.link then
data.isUrl = false
data.link = args.link
data.label = args.label
-- Dummy button as has no link or url
elseif not args.url and not args.link then
data.label = args.label
end
end
 
local class = args.class and args.class:lower()
--- If error has occured contains error string, or `nil`.
if class == 'ui-button-green'
---@type string|nil
or class == 'ui-button-blue'
data.error = nil
or class == 'ui-button-red'
--- Error if no aria-label and no visible label
then
if (not data.label and not args.aria_label
return '[[Category:Pages using old style ui-button-color]]'
and not args.disabled and not args.ariaDisabled) then
data.error = '<span class="error"><strong>Preview warning:</strong>'
.. ' A button without a visible label '
.. 'needs an [[WAI-ARIA|ARIA]] label, please define it using '
.. '"aria-label".</span>'
end
 
--- Classes for button span tag
---@type table
data.classes = { 'cdx-button', 'cdx-button--fake-button' }
local class = type(args.class) == 'string' and args.class
or ''
local action = type(args.action) == 'string' and args.action:lower()
or 'default' -- or 'default' by default
local weight = type(args.weight) == 'string' and args.weight:lower()
or 'normal' -- or 'normal' by default
local size  = type(args.size) == 'string' and args.size:lower()
or 'medium' -- or 'medium' by default
table.insert(data.classes, 'cdx-button--action-' .. action)
table.insert(data.classes, 'cdx-button--weight-' .. weight)
table.insert(data.classes, 'cdx-button--size-' .. size)
if class then
table.insert(data.classes, class) -- Custom class
end
 
--- Disabled, greyed-out state of button
---@type boolean
data.disabled = args.disabled
if data.disabled then
table.insert(data.classes, 'cdx-button--fake-button--disabled')
else
else
table.insert(data.classes, 'cdx-button--fake-button--enabled')
end
if type(args.icon) == 'string' then
--- Icon for button
---@type string
local icon = args.icon:lower()
data.iconSpan = html.create('span')
data.iconSpan:addClass('cdx-button__icon cdx-demo-css-icon--' .. icon)
data.iconSpan:attr('aria-hidden', 'true')
if not data.label then
-- Icon-only button, add extra class for styling
table.insert(data.classes, 'cdx-button--icon-only')
end
end
-- Label length checks
if data.label then
if len(data.label) > 38 then
local errorMsg ='<span class="error"><strong>Preview warning:'
.. '</strong> A button label '
.. 'should ideally be shorter than 38 characters, see '
.. '[[en:Template:Clickable button/doc#Button label length|documentation]].'
.. '</span>'
data.error = data.error and (data.error .. ' ' .. errorMsg) or errorMsg
elseif len(data.label) < 3 then
table.insert(data.classes, 'cdx-button--short-label')
end
end
data.aria_label = args.aria_label
data.ariaDisabled = args.ariaDisabled
return data
end
--- **Interface for other Lua modules.**
--- Function can be called by other Lua modules to generate wikitext
--- without pre-processing arguments with [[Module:Arguments]], adding
--- TemplateStyles, and returning blank string if no arguments were given.
---@param args table Module's arguments.
---@return string data Wikitext that renders button, without CSS file.
function p._main(args)
---@type table Parsed arguments.
local parsedArgs = parseParameters(args)
---@type table Raw data such as element attributes, values, and contents.
local data = makeLinkData(parsedArgs)
parsedArgs.label = data.label
parsedArgs.ariaDisabled = data.ariaDisabled or false
data.categories = renderTrackingCategories(parsedArgs)
return renderLink(data)
end
--- **Interface for templates.**
--- Main function called by templates to use this module.
--- Using the `{{#invoke:Clickable button|main|arguments}}` parser function.
---@deprecated
---@class frame: string
---@param frame frame
---@return string Returns wikitext for insertion in a wiki page.
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = {
'Template:Clickable button',
'Template:Clickable button/sandbox',
'Template:Cdx-button'
}
})
-- Return empty string if no arguments supplied
local hasInput = false
for _, v in pairs(args) do
if v and v ~= "" then
hasInput = true
break
end
end
if not hasInput then
return ''
return ''
end
end
--[[ TESTING
local returnValue = p._main(args)
local templateStyle = frame:extensionTag(
'templatestyles', '', { src = 'Template:Clickable button/styles.css' }
)
do
local returnS1 = html.create('div')
local lexer = require('Module:Lua lexer')
returnS1:addClass('cdx-message')
returnS1:addClass('cdx-message--block')
local returnS2 = html.create('span')
returnS2:addClass('cdx-message__icon')
local returnS3 = html.create('div')
returnS3:addClass('cdx-message__content')
returnS3:attr('font-size', 'small')
returnValue = tostring(returnValue)
returnValue = tostring(lexer(returnValue))
local returnS4 = frame:extensionTag('syntaxhighlight',
returnValue , { lang = 'lua' } )
returnValue = templateStyle ..
tostring(returnS1:node(returnS2):done():node(returnS3):node(returnS4):allDone())
end
return returnValue
-- ]]
return frame:extensionTag(
'templatestyles', '', { src = 'Template:Clickable button/styles.css' }
) .. p._main(args)
end
end


return p
return p

Latest revision as of 17:55, 12 August 2026

Module documentation[ view · edit · history · purge ]
This documentation is transcluded from Module:Clickable button/doc.

Template:Template rating

Template:Uses templatestyles

Generates wikitext for clickable Codex button. Renders the button component from the Codex design system for Wikimedia. Includes helper functions for URL parsing and cleaning, adding tracking categories. Intended for use in templates and other modules. Implements Template:Clickable button and others. Supports legacy parameters.

  • Options to include an icon or create an icon-only button.
  • Target a URL or a wikilink
  • Set the weight, size and state of the button (enabled or disabled).
  • Dummy button creation can be disabled.

For more information on appropriate usage of UI buttons, see the Codex documentation.

  • Inserts two CSS files. Module:Clickable button/styles.css is required and makes minor tweaks for word-wrapping if the visible label is too long, centering or aligning button left or right, and minimum widths as is needed for icon-only buttons and labels containing two characters or less.
  • The second CSS file, Module:Clickable button/icons.css, is prepended to the button's HTML only if an icon is used.
  • Supports legacy parameters from previous templates.

Usage in wikitext

edit

Some arguments are case-insensitive.

{{#invoke:Clickable button|main
| 1        = <!-- Alias for wikilink -->
| 2        = <!-- Alias for label -->
| label    = <!-- Button visible text label -->
| link     = <!-- Target wikilink -->
| url      = <!-- Target external URL -->
<!-- Inputs action, weight, size, and icon are case-insensitive -->
| action   = <!-- progressive | destructive | default: default. -->
| weight   = <!-- primary | quiet | default: normal. -->
| size     = <!-- small | large | default: medium. Automatically chooses size based on line-height and device. -->
| icon     = <!-- Name of icon, stored in [[Module:Clickable button/icons.css]] e.g., search  -->
| disabled = <!-- `true` or any other true value like `1` or `yes`. -->
| aria-label = <!-- [[w:ARIA]] label for accessibility DOM tree. -->
| nocat      = <!-- `true` to not auto-categorize. -->
<!-- Others -->
| category = <!-- Category name e.g., Category:Name or Name or [[Category:Name]] -->
| class    = <!-- Custom CSS class without quotation marks -->
| style    = <!-- Custom CSS styling without quotation marks -->
<!-- Legacy arguments -->
| color    = <!-- blue | red --> 
}}

Usage in other modules

edit

Ensure you know what to expect from the function you call from another module.

  • function p.main(frame) emits TemplateStyles for the CSS files with the wikitext, and pre-processes the arguments in a frame using Module:Arguments, e.g. ignore blank values'', and trim trailing whitespace.
  • function p._main(arguments) Parses the arguments such as lowercase appropriate arguments, account for use of legacy parameters and decides whether aria-disabled should be true.
  • function p.url(url, [label]) is available, not for button creation, but as an adaption of Module:URL to clean and normalise a URL string and optionally generate a label.
  • The module's other functions, such as makeLinkData() and renderLink(), are localised/local to the module and would need to be made global first to be accessible to other modules.

To call p.main() for example, use:

local createButton = require( 'Module:Clickable button/sandbox' )
buttonWikitext = createButton.main( {
    link = 'South Africa',
    label = 'Go to South Africa',
    action = 'progressive'
    weight = 'default',
    size = 'medium',
    icon = 'link-external',
} ) 
return buttonWikitext

and the value of buttonWikitext would be:

<<templatestyles src="Module:Cdx-button/styles.css" /><templatestyles src="Module:Cdx-button/icons.css" /><span class="cdx-button cdx-button--fake-button cdx-button--action-progressive cdx-button--weight-quiet cdx-button--size-medium" role="button" aria-disabled="false"><span class="cdx-button__icon cdx-demo-css-icon--link-external" aria-hidden="true"></span>Go to South Africa</span>

Function _main would output:

<span class="cdx-button cdx-button--fake-button cdx-button--action-progressive cdx-button--weight-quiet cdx-button--size-medium" role="button" aria-disabled="false"><span class="cdx-button__icon cdx-demo-css-icon--link-external" aria-hidden="true"></span>Go to South Africa</span>

As a result, unless a CSS file is added to give the appropriate class an icon, the icon will not render.

Implementation

edit

Length of visible label

edit

See the Codex button component documentation.


--------------------------------------------------------------------------------
--- @module 'CodexClickableButton'
--- Generates wikitext for clickable Codex button.
--- 
--- Outputs wikitext to render the (button component)[mdoc:codex/latest/components/demos/button.html]
--- from the (Codex design system for Wikimedia)[https://doc.wikimedia.org/codex/latest].
---- Options to include an icon or create an icon-only button.
---- Target a URL or a wikilink
---- Set the weight, size and state of the button (enabled or disabled).
---- Dummy button creation can be disabled.
---
--- Includes helper functions for URL parsing and cleaning, and adding tracking 
--- categories. Intended for use in templates and other modules.
--- Supports legacy parameters. To add icons, see CSS link in constants below.
---
--- @author [[User:Waddie96]]
--- @license CC-BY-SA-4.0/GFDL
--- @class CodexClickableButton extends ClickableButton
---  Table containing arguments for the button.
--- @class args table
--- @field label? string The button's visible text label.
--- @field link? string|'no' The target wikilink for the button.
--- @field url? string The target external URL for the button.
--- @field icon? string The name of the icon to display found in CSS file.
--- @field color? 'blue'|'green'|'red'|string Legacy color parameter.
--- @field class? string Custom CSS classes for the button.
--- @field weight? 'quiet'|'normal'|'primary' The visual weight of the button.
--- @field size? 'small'|'medium'|'large' The size of the button.
--- @field action? 'progressive'|'destructive'|'default'|string The action type of the button.
--- @field disabled? boolean|'1'|string Whether the button is disabled/greyed out. `disabled` is `true` if: `link` = `'no'` or `false` or `disabled` = `'1'` or `true`.
--- @field style? string Custom inline CSS styles.
--- @field nocat? boolean|string If `true`, suppresses tracking categories.
--- @field category? string An additional category to add.
--- @field aria-label? string The ARIA label for accessibility.
--- @field arialabel? string (alias for aria-label)
--- @field aria_label? string (alias for aria-label)
--- @field [1]? string Positional argument 1 (alias for link/label).
--- @field [2]? string Positional argument 2 (alias for label).
--- @var categories? string|boolean Additional categories to add.
--- @var ariaDisabled? boolean Internal flag indicating if the button is functionally disabled for ARIA.
--- @var oldClassMatched string|boolean Internal flag for outdated classes.
--- @var isUrl boolean Whether the link is a URL.
--- @var errorText string|nil 
--- @var tblClasses table Classes for the button span tag.
--- @var pageTitle mw.title Title of the current page.
--- @todo [[Module:Neturl]] [[Module:Check for unknown parameters]]

local yesno = require('Module:Yesno')
local delink = require('Module:Delink')._delink

local p = {}

function p.main(frame)
	local getArgs = require('Module:Arguments').getArgs
	local args = getArgs(frame)
	return p._main(args)
end

function p._main(args)
	-- If first arg or a url is not provided,
	-- but we have a second arg, make a button.
	-- Otherwise, return nothing.
	args.originalInput = args[1]
	args[1] = delink({args[1]})
	if args[1] == "" then
		args[1] = nil
	end

	if not args[1] and not args.url then
		if args[2] then
			p.nolink = true
		else
			return ''
		end
	end

	local data = p.makeLinkData(args)
	local link = p.renderLink(args.originalInput, data)
	local trackingCategories = p.renderTrackingCategories(args)
	return link .. trackingCategories
end

function p.makeLinkData(args)
	local data = {}

	-- Get the link and display values,
	-- and find whether we are outputting
	-- a wikilink or a URL.
	if args.url then
		data.isUrl = true
		data.link = args.url
		if args[1] then
			data.display = args[1]
		elseif args[2] then
			data.display = args[2]
		else
			data.display = args.url
			p.urlisdisplay = true
		end
	else
		data.isUrl = false
		p.urlisdisplay = false
		data.link = args[1]
		if args[2] then
			data.display = args[2]
		else
			data.display = args[1]
		end
		if args[1] and args[1]:find('http') then
			data.isUrl = true
		end
	end
	
	if yesno(args.link) == false then
		p.nolink = true
	end

	-- Colours
	-- For the merge with {{clickable button}}
	local colour = args.color and args.color:lower()

	-- Classes
	local class = args.class and args.class:lower()
	data.classes = {}
	if class == 'ui-button-green'
		or class == 'ui-button-blue'
		or class == 'ui-button-red'
	then
		table.insert(
			data.classes,
			'submit ui-button ui-widget ui-state-default ui-corner-all'
				.. ' ui-button-text-only ui-button-text'
		)
	else
		table.insert(data.classes, 'mw-ui-button')
	end
	
	--If class is unset,
	--then let color determine class
	if not class then
		if colour == 'blue' then
			class = 'mw-ui-progressive'
		elseif colour == 'red' then
			class = 'mw-ui-destructive'
		elseif colour == 'green' then
			class = 'mw-ui-constructive'
		end
	end
	
	if class then
		table.insert(data.classes, class)
	end

	-- Styles
	do
		--[[
		-- Check whether we are on the same page as we have specified in
		-- args[1], but not if we are using a URL link, as then args[1] is only
		-- a display value. If we are currently on the page specified in
		-- args[1] make the button colour darker so that it stands out from
		-- other buttons on the page.
		--]]
		local success, linkTitle, currentTitle
		if not data.isUrl then
			currentTitle = mw.title.getCurrentTitle()
			success, linkTitle = pcall(mw.title.new, args[1])
		elseif p.urlisdisplay then
			currentTitle = mw.title.getCurrentTitle()
		end
		if success
			and linkTitle
			and mw.title.equals(currentTitle, linkTitle)
			and not p.urlisdisplay
		then
			if class == 'ui-button-blue'
				or class == 'mw-ui-progressive'
				or class == 'mw-ui-constructive'
			then
				data.backgroundColor = '#2962CB'
				data.color = '#fff'
			elseif class == 'ui-button-green' then
				data.backgroundColor = '#008B6D'
			elseif class == 'ui-button-red' or class == 'mw-ui-destructive' then
				data.backgroundColor = '#A6170F'
			else
				data.backgroundColor = '#CCC'
				data.color = '#666'
			end
		elseif p.urlisdisplay then
			data.dummyLink = tostring(currentTitle)
		end
		-- Add user-specified styles.
		data.style = args.style
	end
	return data
end

function p.renderLink(originalInput, data)
	-- Render the display span tag.
	local display
	do
		local displaySpan = mw.html.create('span')
		for i, class in ipairs(data.classes or {}) do
			displaySpan:addClass(class)
		end

		displaySpan
			:css{
				['background-color'] = data.backgroundColor,
				color = data.color
			}
		if data.style then
			displaySpan:cssText(data.style)
		end
		displaySpan:wikitext(data.display)
		display = tostring(displaySpan)
	end

	-- Render the link
	local link
	if originalInput and originalInput:find('|') then
		link = string.format('[[%s|%s]]', delink({originalInput, wikilinks = 'target'}), display)
	elseif p.nolink then
		if p.urlisdisplay then
			link = string.format('[[%s|%s]]', data.dummyLink, display)
		else
			link = string.format('%s', display)
		end
	else
		if data.isUrl then
			link = string.format('[%s %s]', data.link, display)
		else
			link = string.format('[[%s |%s]]', data.link, display)
		end
	end

	return string.format('<span class="plainlinks clickbutton">%s</span>', link)
end

function p.renderTrackingCategories(args)
	if yesno(args.category) == false then
		return ''
	end
	local class = args.class and args.class:lower()
	if class == 'ui-button-green'
		or class == 'ui-button-blue'
		or class == 'ui-button-red'
	then
		return '[[Category:Pages using old style ui-button-color]]'
	else
		return ''
	end
end

return p
Cookies help us deliver our services. By using our services, you agree to our use of cookies.