Module:Clickable button/sandbox2

-- [[w:en:Module:Clickable button]]
-- Builds Codex's button component. See [[wmdoc:codex/latest]].
-- Implements [[Template:Clickable button]] and others.
-- To add icons: [[Template:Clickable button/styles.css]].

-- TRACKING CATEGORIES: [[Category:Pages using clickable dummy button]]
-- [[Category:Pages using clickable button with external links]]
-- [[Category:Pages using clickable button with outdated classes]]
-- unless nocat= is true value. Adds category= any custom category regardless of nocat=.

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

local p = {}

-- Cleans up and validates a URL.
-- Copied from [[en:Module:URL]] with minor modifications.
local function safeUri(s)
	local success, uri = pcall(function()
		return mw.uri.new(s)
	end)
	if success then
		return uri
	end
end

local function extractUrl(extract)
	local url = extract
	url = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])',
		'http%1://%3')
	local uri = safeUri(url);
	if uri and uri.host then
		return url
	end
end

local function _url(url, text)
	url = mw.text.trim(url or '')
	text = mw.text.trim(text or '')

	if url == '' then
		return text
	end

	-- If the URL contains any unencoded spaces, encode them, because MediaWiki will otherwise interpret a space as the end of the URL.
	url = mw.ustring.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 = mw.ustring.gsub(url, '#$', '')
	url = mw.ustring.gsub(url, '%?$', '')

	-- If it's an http(s) URL without the double slash, fix it.
	url = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3')

	local uri = safeUri(url)

	-- Handle URL's without a protocol and URL's that 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 = mw.ustring.lower(uri.host or '') .. port .. (uri.relativePath or '')

			-- Add <wbr> before _/.-# sequences
			text = mw.ustring.gsub(text, "(/+)", "<wbr/>%1") -- This entry MUST be the first. "<wbr/>" has a "/" in it, you know.
			text = mw.ustring.gsub(text, "(%.+)", "<wbr/>%1")
			-- text = mw.ustring.gsub(text,"(%-+)","<wbr/>%1") 	-- DISABLED for now
			text = mw.ustring.gsub(text, "(%#+)", "<wbr/>%1")
			text = mw.ustring.gsub(text, "(_+)", "<wbr/>%1")
		else -- URL is badly-formed, so just display whatever was passed in
			text = url
		end
	end

	return url, text
end

local function url(URL, TEXT)
	local s = URL or ''
	local text = TEXT or ''
	s = s or extractUrl(s) or extractUrl(text) or ''
	-- Strip out HTML tags and [ ] from URL
	s = (s or ''):gsub("<[^>]*>", ""):gsub("[%[%]]", "")
	-- Truncate anything after a space
	s = s:gsub("%%20", " "):gsub(" .*", "")
	return _url(s, text)
end

-- Renders tracking categories based on parameters.
local function renderTrackingCategories(args)
	local categories = ''
	local class = args.class and args.class:lower() or ''
	---- local check_for_unknown_parameters = require("Module:Check for unknown parameters")._check
	---- local title = mw.title.getCurrentTitle()

	-- Don't add categories if nocat=yes, but still add any custom category.
	-- Custom category passed in
	if args.category and yesno(args.nocat) == false then
		local q = args.category
		q = q:gsub('%[%[', ''):gsub('%]%]', ''):gsub('[Cc]ategory:', '')
		categories = categories .. '[[' .. 'Category:' .. q .. ']]'
	end
	if yesno(args.nocat) == true then
		return ''
	end
	mw.logObject(args, categories) -- DEBUG

	--[=[
	categories = categories .. check_for_unknown_parameters({
		checkpositional = "y",
		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) ]=]

	-- @TODO: whether all dummy buttons should get the dummy-category,
	-- or only those without disabled/ariaDisabled?
	if ((not args.link and not args.url
		and not args.disabled and not args.ariaDisabled)) or
		(args.link or args.url) and (not args.label) then
		-- Dummy button == no link, no url and not disabled
		-- OR link/url but no visible label
		categories = categories .. '[[Category:Pages using clickable dummy button]]'
	elseif (not args.link and not args.url
			and (args.disabled or args.ariaDisabled)) then
		-- Disabled button
		categories = categories .. '[[Category:Pages using disabled dummy button]]'
	end
	if class == 'ui-button-green'
		or class == 'ui-button-blue'
		or class == 'ui-button-red'
		or class == 'mw-ui-progressive'
		or class == 'mw-ui-destructive' then
		categories = categories .. '[[Category:Pages using clickable button with outdated classes]]'
	end
	if args.url then
		categories = categories .. '[[Category:Pages using clickable button with external links]]'
	end
	if class == 'mw-ui-constructive' then
		categories = categories .. '[[Category:Pages using clickable button with deprecated parameters]]'
	end
	mw.logObject(categories)
	return categories
end

local function renderLink(data)
	-- Build span tag
	local span = mw.html.create('span')
	for _, class in ipairs(data.classes or {}) do
		span:addClass(class)
	end
	span:attr('role', 'button')
	if data.aria_label then
		span:attr('aria-label', data.aria_label)
	end
	-- ARIA disabled attribute for disabled/no-link/dummy buttons
	if data.disabled or data.ariaDisabled then
		span:attr('aria-disabled', 'true')
	elseif data.disabled == false then
		span:attr('aria-disabled', 'false')
	end
	if data.iconSpan then
		span:node(data.iconSpan)
	end
	if data.label then
		span:wikitext(data.label)
		--[[ span:node(mw.html.create('span')
			:addClass('cdx-button--text')
			:wikitext(data.label)) ]]
	end

	local display = tostring(span)

	if data.disabled then
		return string.format('%s %s', display, data.categories)
	end
	if data.isUrl then
		---- mw.logObject(data)
		return string.format('<span class="plainlinks">[%s %s]</span> %s',
			data.url, display, data.categories)
	elseif data.isUrl == false then
		return string.format('[[%s|%s]] %s', data.link, display, data.categories)
	else
		-- No url/link provided
		return string.format('%s %s', display, data.categories)
	end
end

-- Backward compatibility for deprecated parameters
local function parseParameters(args)
	-- It's weird that we may make a link a label above, but if we truly
	-- only got 1=, then that would mean it's intentional to make both the link
	-- and label the same.
	-- Ensure label is set from priority: label= > 2= > 1=
	args.label = args.label or args[2] or args[1]

	-- Disable if link=no or disabled=1
	args.disabled = (yesno(args.link) == false)
		or yesno(args.disabled)
	args.link = args.link or args[1]

	-- Remove positional args after assigning
	args[1] = nil
	args[2] = nil

	-- Make aria-disabled=true later on if no link
	if (args.link and yesno(args.link) ~= false) or args.url then
		args.ariaDisabled = false
	else
		-- If no link whatsoever, make dummy button.
		-- But for accessibility, ARIA must know it won't do anything.
		args.ariaDisabled = true
		-- OPTION to forcefully disable dummy buttons.
		---- args.disabled = 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()
	local class = type(args.class) == 'string' and args.class:lower()
	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

	return args
end

-- Constructs attributes for the HTML elements.
local function makeLinkData(args)
	local data = {}

	-- Decide link vs. url vs. none
	-- URL has priority over link if both provided. Also, clean URL
	if args.url then
		data.isUrl = true
		-- Make pretty URL and label based on URL if no label.
		--[[ local URI = require "URI"
		local uri = URI:new(args.url)
		data.url = uri
		local label = uri:host() .. uri:path()
		if label:len() > 20 then
			label = uri:host()
		end ]]
		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
	elseif not args.url and not args.link then
		-- Dummy button, no link or url
		data.label = args.label
	end

	-- @TODO: Error tracking category
	-- Error if no aria-label and no visible label
	if (not data.label and not args.aria_label
		and not args.disabled and not args.ariaDisabled) then
		error('A button without a visible label needs an [[WAI-ARIA|ARIA]] '
		.. 'label, please define it using "aria-label"', 2)
	end

	-- Classes
	data.classes = {'cdx-button', 'cdx-button--fake-button'}
	local class  = type(args.class) == 'string' and args.class:lower(args.class)
	local action = type(args.action) == 'string' and args.action:lower()
		or '' -- or 'default' by default
	local weight = type(args.weight) == 'string' and args.weight:lower()
		or '' -- or 'normal' by default
	local size   = type(args.size) == 'string' and args.size:lower()
		or '' -- 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)
	table.insert(data.classes, class) -- Custom class

	-- Disabled state
	data.disabled = args.disabled
	if data.disabled then
		table.insert(data.classes, 'cdx-button--fake-button--disabled')
	else
		table.insert(data.classes, 'cdx-button--fake-button--enabled')
	end

	-- Icon
	local icon = type(args.icon) == 'string' and args.icon:lower()
	if icon then
		data.iconSpan = mw.html.create('span')
			:addClass('cdx-icon cdx-button__icon cdx-demo-css-icon--' .. icon)
			: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 string.len(data.label) > 40 then
			error('Buttons labels should ideally be fewer than 38 characters' ..
			', see [[Template:Clickable button#Button label length|' ..
			'documentation]]', 2) -- @TODO: Preview warning only.
		end
		-- Short label min-width custom CSS adjustment per Codex documentation.
		if string.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
	---- data.nocat = args.nocat
	---- data.category = args.category

	return data
end

local function _main(args)
	---- local backupArgs = args
	local parsedArgs = parseParameters(args)
	local data = makeLinkData(parsedArgs)
	data.categories = renderTrackingCategories(parsedArgs)

	return renderLink(data)
end

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 were 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 ''
	end

	return frame:extensionTag(
		'templatestyles', '', { src = 'Template:Clickable button/styles.css' }
	) .. _main(args)
end

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.