Module:Forumlink: Difference between revisions

From NPOWiki
Jump to navigation Jump to search
news uses a category, guess it'll be manual
better code for title capitalization
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
local err = require('Module:Error').call
local lang = mw.language.getContentLanguage()
local p = {}
local p = {}
local largs
local largs
Line 5: Line 7:
--Can override using same key as in types
--Can override using same key as in types
local presets = {
local presets = {
npo = { domain = 'npowned.net', type = 'invision',
npo = { domain = 'npowned.net', type = 'invision', name='NPO forums',
forum = 'forums/forum/%s/', topic = 'forums/topic/%s/', default = 'forums/' },
forum = 'forums/forum/%s/', topic = 'forums/topic/%s/', default = 'forums/' },
cn = { domain = 'forums.cybernations.net', type='invision' },
cn = { domain = 'forums.cybernations.net', type='invision', name='Cyber Nations forums' },
ns = { domain = 'forum.nationstates.net', type='phpbb' },
ns = { domain = 'forum.nationstates.net', type='phpbb', name='NationStates forums' },
tsp = { domain = 'tspforums.xyz', type='mybb' },
tsp = { domain = 'tspforums.xyz', type='mybb', name='The South Pacific forums' },
tsparchive = { domain = 'archive.tspforums.xyz', type='mybbold' },
tsparchive = { domain = 'archive.tspforums.xyz', type='mybbold', name='The South Pacific forum archive' },
}
}


Line 62: Line 64:
return largs[arg]
return largs[arg]
end
end
end
--Convert a slugified string to a naturally formatted title.
--This makes many assumptions for simplicity, so for accuracy, specifying the display text is preferred.
--If the input is numeric, an empty string will be returned.
local function slugToTitle(slug, ftype)
if tonumber(slug) then
return ''
end
local result = ''
local sep = ftype.sep
if sep == '' then
sep = '-'
end
local function makeSet(t)
local set = {}
for i, v in ipairs(t) do
set[v] = true
end
return set
end
local keepLowercase = makeSet({'a', 'an', 'and', 'in', 'for', 'from', 'of', 'on', 'the', 'to'})
local keepUppercase = makeSet({'npo', 'ns', 'cn', 'lt', 'nco'})
local mixedCase = {
['lts'] = 'LTs',
['ncos'] = 'NCOs',
}
for part in mw.text.gsplit(slug, sep, true) do
local add = ''
if keepLowercase[part] then
--Words to keep lowercase, except if first
if result ~= '' then
add = part
else
add = lang:ucfirst(part)
end
elseif keepUppercase[part] then
--Words to make all uppercase
add = mw.ustring.upper(part)
elseif mixedCase[part] then
--Words to capitalize partially
add = mixedCase[part]
elseif result == '' and tonumber(part) then
--Do not include initial ID in parameter
add = ''
elseif mw.ustring.sub(part, 1, 1) == 'r' and tonumber(mw.ustring.sub(part, 2)) then
--Do not include ID suffix in news posts
add = ''
else
add = lang:ucfirst(part)
end
if add ~= '' then
if result ~= '' then
result = result .. ' '
end
result = result .. add
end
end
return result
end
end


Line 124: Line 187:
function p.call(args)
function p.call(args)
largs = args-- lazy shortcut for local args
largs = args-- lazy shortcut for local args
local ftype, typename, url, domain, display
local ftype, typename, url, domain
if argDefault('http') then
if argDefault('http') then
url = 'http://'
url = 'http://'
Line 139: Line 202:
end
end
if not domain then
if not domain then
return '<span class="error">missing site address</span>'
return err('missing site address')
end
end
if not ftype then
if not ftype then
return '<span class="error">missing forum type</span>'
return err('missing forum type')
end
end
ftype = mw.ustring.lower(ftype)
ftype = mw.ustring.lower(ftype)
Line 148: Line 211:
ftype = types[ftype]
ftype = types[ftype]
if not ftype then
if not ftype then
return '<span class="error">type is invalid or unrecognized</span>'
return err('type is invalid or unrecognized')
end
end
url = url .. domain .. '/'
url = url .. domain .. '/'
Line 163: Line 226:
end
end
if component2 ~= '' and not argDefault(component2) then
if component2 ~= '' and not argDefault(component2) then
return '<span class="error">' .. component2 .. ' is required to link to ' .. component1 .. '</span>'
return err(component2 .. ' is required to link to ' .. component1)
end
end
if component1 == 'post' and component2 == 'topic' then
if component1 == 'post' and component2 == 'topic' then
Line 179: Line 242:
end
end
display = argDefault(2)
local display = argDefault(2, '')
if not display then
local title = argDefault('title')
if component1 == 'default' then
local forumName = argDefault('forumname')
display = args[1] .. ' forums'
if display == '' then
--Generate display text based on parameters
if component1 == 'post' then
display = 'Post'
elseif component1 ~= 'default' then
if not title then
if component1 == 'news' then
--Remove category from news before converting
title = slugToTitle(mw.text.split(args[component1], '/', true)[2], ftype)
else
title = slugToTitle(args[component1], ftype)
end
end
display = lang:ucfirst(component1)
if title ~= '' then
display = display .. ' "' .. title .. '"'
end
end
if component2 == 'post' then
display = 'Post in ' .. lang:lcfirst(display)
end
if preset or forumName then
if display ~= '' then
display = display .. ' on the '
end
if preset then
if preset.name then
display = display .. preset.name
else
display = display .. args[1] .. ' forums'
end
elseif forumName then
display = display .. forumName
end
else
else
display = args[component1]
if display ~= '' then
display = display .. ' on forums at '
end
display = display .. domain
end
end
end
end

Latest revision as of 03:54, 25 November 2025

Documentation [edit]

This page is a stub - it only covers the very basics of its subject. More information should be added to make the page informative and useful. If no more information is available, the page should be considered for a merge, redirect, or deletion.

Details: documentation to be written

If you can correct the issue, please edit the page to do so, then remove this notice.

Please see Template:Forumlink for usage information. Use the template rather than invoking the module.

Here are some test cases to run (will need to add more for other parameters and create a testcases function):

=p.call({'NPO', topic='196400-an-update-on-fundraising-for-the-third-faction'})
=p.call({'NPO', topic='107263-new-colonel-lts-and-ncos'})
=p.call({'NPO', topic='181871-npo-branch-member-sign-in', post='6349740'})
=p.call({'NPO', news='torn/official-opening-of-valour-r2782'})

The above documentation is transcluded from Module:Forumlink/doc.

local err = require('Module:Error').call
local lang = mw.language.getContentLanguage()
local p = {}
local largs

--Keys must be lowercase
--Can override using same key as in types
local presets = {
	npo = { domain = 'npowned.net', type = 'invision', name='NPO forums',
		forum = 'forums/forum/%s/', topic = 'forums/topic/%s/', default = 'forums/' },
	cn = { domain = 'forums.cybernations.net', type='invision', name='Cyber Nations forums' },
	ns = { domain = 'forum.nationstates.net', type='phpbb', name='NationStates forums' },
	tsp = { domain = 'tspforums.xyz', type='mybb', name='The South Pacific forums' },
	tsparchive = { domain = 'archive.tspforums.xyz', type='mybbold', name='The South Pacific forum archive' },
}

--Keys must be lowercase
--If parameters are numerical only, set sep to ''
local types = {
	invision = {
		sep = '-',
		announcement = 'announcement/%s/',
		forum = 'forum/%s/',
		news = 'news/%s/',
		profile = 'profile/%s/',
		topic = 'topic/%s/',
		post = '?do=findComment&comment=%s',
		default = 'index.php',
		postRequiresTopic = true
	},
	mybb = {
		sep = '',
		forum = 'forum-%s.html',
		profile = 'user-%s.html',
		topic = 'thread-%s.html',
		post = '-post-%s.html#pid%s',
		default = 'index.php',
		postRequiresTopic = true
	},
	mybbold = {
		sep = '',
		forum = 'forumdisplay.php?fid=%s',
		profile = 'member.php?action=profile&uid=%s',
		topic = 'showthread.php?tid=%s',
		post = '&pid=%s#pid%s',
		default = 'index.php',
		postRequiresTopic = true
	},
	phpbb = {
		sep = '',
		forum = 'viewforum.php?f=%s',
		profile = 'memberlist.php?mode=viewprofile&u=%s',
		topic = 'viewtopic.php?t=%s',
		post = 'viewtopic.php?p=%s#p%s',
		default = 'index.php',
		postRequiresTopic = false
	},
}

local function argDefault(arg, default)
	if mw.text.trim(largs[arg] or '') == '' then
		return default
	else
		return largs[arg]
	end
end

--Convert a slugified string to a naturally formatted title.
--This makes many assumptions for simplicity, so for accuracy, specifying the display text is preferred.
--If the input is numeric, an empty string will be returned.
local function slugToTitle(slug, ftype)
	if tonumber(slug) then
		return ''
	end
	local result = ''
	local sep = ftype.sep
	if sep == '' then
		sep = '-'
	end
	
	local function makeSet(t)
		local set = {}
		for i, v in ipairs(t) do
			set[v] = true
		end
		return set
	end
	local keepLowercase = makeSet({'a', 'an', 'and', 'in', 'for', 'from', 'of', 'on', 'the', 'to'})
	local keepUppercase = makeSet({'npo', 'ns', 'cn', 'lt', 'nco'})
	local mixedCase = {
		['lts'] = 'LTs',
		['ncos'] = 'NCOs',
	}
	
	for part in mw.text.gsplit(slug, sep, true) do
		local add = ''
		if keepLowercase[part] then
			--Words to keep lowercase, except if first
			if result ~= '' then
				add = part
			else
				add = lang:ucfirst(part)
			end
		elseif keepUppercase[part] then
			--Words to make all uppercase
			add = mw.ustring.upper(part)
		elseif mixedCase[part] then
			--Words to capitalize partially
			add = mixedCase[part]
		elseif result == '' and tonumber(part) then
			--Do not include initial ID in parameter
			add = ''
		elseif mw.ustring.sub(part, 1, 1) == 'r' and tonumber(mw.ustring.sub(part, 2)) then
			--Do not include ID suffix in news posts
			add = ''
		else
			add = lang:ucfirst(part)
		end
		if add ~= '' then
			if result ~= '' then
				result = result .. ' '
			end
			result = result .. add
		end
	end
	return result
end

local function geturl(url, arg1, arg2, preset, ftype, typename)
	--Calculate overrides
	local part1, part2, sep
	if not preset then preset = {} end
	if preset[arg1] then
		part1 = preset[arg1]
	else 
		part1 = ftype[arg1]
	end
	if arg2 ~= '' then
		if preset[arg2] then
			part2 = preset[arg2]
		else
			part2 = ftype[arg2]
		end
	end
	if preset.sep then
		sep = preset.sep
	else
		sep = ftype.sep
	end
	
	if arg1 == 'default' then
		return url .. part1
	end
	
	local text1, text2 = '', ''
	text1 = mw.ustring.lower(largs[arg1])
	if arg2 ~= '' then
		text2 = mw.ustring.lower(largs[arg2])
	end
	
	if sep ~= ' ' then
		--character class: %s is any space character
		text1 = mw.ustring.gsub(text1, '%s', sep)
		text2 = mw.ustring.gsub(text2, '%s', sep)
	end
	
	--printf: %s is a placeholder for a string
	--param passed twice for formats that need it (e.g. phpbb post);
	--  if different params are needed the script will need a rewrite
	--  (Lua doesn't support specifying arg num)
	url = url .. mw.ustring.format(part1, text1, text1)
	if text2 ~= '' then
		url = url .. mw.ustring.format(part2, text2, text2)
	end
	
	if typename == 'mybb' and arg2 == 'post' then
		url = mw.ustring.gsub(url, '.html', '', 1)
	end
	
	return url
end

function p.main(frame)
	return p.call(frame:getParent().args)
end

function p.call(args)
	largs = args-- lazy shortcut for local args
	local ftype, typename, url, domain
	if argDefault('http') then
		url = 'http://'
	else
		url = 'https://'
	end
	local preset = presets[mw.ustring.lower(argDefault(1, ''))]
	if not preset then
		domain = argDefault(1)
		ftype = argDefault('type')
	else
		domain = preset.domain
		ftype = preset.type
	end
	if not domain then
		return err('missing site address')
	end
	if not ftype then
		return err('missing forum type')
	end
	ftype = mw.ustring.lower(ftype)
	typename = ftype
	ftype = types[ftype]
	if not ftype then
		return err('type is invalid or unrecognized')
	end
	url = url .. domain .. '/'
	
	--post has to come first, the rest are just in case multiple params are used accidentally
	local params = {'post', 'topic', 'profile', 'forum', 'news', 'announcement'}
	local component1 = 'default'
	local component2 = ''
	for i, para in ipairs(params) do
		if argDefault(para) then
			component1 = para
			if para == 'post' and ftype.postRequiresTopic then
				component2 = 'topic'
			end
			if component2 ~= '' and not argDefault(component2) then
				return err(component2 .. ' is required to link to ' .. component1)
			end
			if component1 == 'post' and component2 == 'topic' then
				component1 = 'topic'
				component2 = 'post'
			end
			break
		end
	end
	
	url = geturl(url, component1, component2, preset, ftype, typename)
	
	if argDefault('numbered') then
		return '[' .. url .. ']'
	end
	
	local display = argDefault(2, '')
	local title = argDefault('title')
	local forumName = argDefault('forumname')
	if display == '' then
		--Generate display text based on parameters
		if component1 == 'post' then
			display = 'Post'
		elseif component1 ~= 'default' then
			if not title then
				if component1 == 'news' then
					--Remove category from news before converting
					title = slugToTitle(mw.text.split(args[component1], '/', true)[2], ftype)
				else
					title = slugToTitle(args[component1], ftype)
				end
			end
			display = lang:ucfirst(component1)
			if title ~= '' then
				display = display .. ' "' .. title .. '"'
			end
		end
		
		if component2 == 'post' then
			display = 'Post in ' .. lang:lcfirst(display)
		end
		
		if preset or forumName then
			if display ~= '' then
				display = display .. ' on the '
			end
			if preset then
				if preset.name then
					display = display .. preset.name
				else
					display = display .. args[1] .. ' forums'
				end
			elseif forumName then
				display = display .. forumName
			end
		else
			if display ~= '' then
				display = display .. ' on forums at '
			end
			display = display .. domain
		end
	end
	return '[' .. url .. ' ' .. display .. ']'
end

return p