Module:Forumlink: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
better code for title capitalization |
||
| (7 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 | ||
--Keys must be lowercase | --Keys must be lowercase | ||
--Can override using same key as in types | |||
local presets = { | local presets = { | ||
npo = { domain = 'npowned.net', type = ' | 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 | --Keys must be lowercase | ||
--If parameters are numerical only, set sep to '' | |||
local types = { | local types = { | ||
invision = { | |||
sep = '-', | sep = '-', | ||
announcement = 'announcement/%s/', | announcement = 'announcement/%s/', | ||
forum = ' | forum = 'forum/%s/', | ||
news = 'news | news = 'news/%s/', | ||
profile = 'profile/%s/', | profile = 'profile/%s/', | ||
topic = ' | topic = 'topic/%s/', | ||
default = ' | 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 | |||
}, | |||
} | } | ||
| Line 28: | Line 66: | ||
end | end | ||
local function geturl(url, | --Convert a slugified string to a naturally formatted title. | ||
if | --This makes many assumptions for simplicity, so for accuracy, specifying the display text is preferred. | ||
return url .. | --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 | end | ||
if | if typename == 'mybb' and arg2 == 'post' then | ||
url = mw.ustring.gsub(url, '.html', '', 1) | |||
end | end | ||
return url | |||
return url | |||
end | end | ||
| Line 45: | 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, url, domain | local ftype, typename, url, domain | ||
if argDefault('http') then | if argDefault('http') then | ||
url = 'http://' | url = 'http://' | ||
| Line 60: | Line 202: | ||
end | end | ||
if not domain then | if not domain then | ||
return ' | return err('missing site address') | ||
end | end | ||
if not ftype then | if not ftype then | ||
return ' | return err('missing forum type') | ||
end | end | ||
ftype = | ftype = mw.ustring.lower(ftype) | ||
typename = ftype | |||
ftype = types[ftype] | |||
if not ftype then | if not ftype then | ||
return ' | return err('type is invalid or unrecognized') | ||
end | end | ||
url = url .. domain .. '/' | url = url .. domain .. '/' | ||
local params = {'topic', 'profile', 'forum', 'news', 'announcement'} | --post has to come first, the rest are just in case multiple params are used accidentally | ||
local | local params = {'post', 'topic', 'profile', 'forum', 'news', 'announcement'} | ||
local component1 = 'default' | |||
local component2 = '' | |||
for i, para in ipairs(params) do | for i, para in ipairs(params) do | ||
if argDefault(para) then | 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 | break | ||
end | end | ||
end | end | ||
url = geturl(url, | |||
url = geturl(url, component1, component2, preset, ftype, typename) | |||
if argDefault('numbered') then | if argDefault('numbered') then | ||
| Line 85: | Line 242: | ||
end | end | ||
display = argDefault(2) | local display = argDefault(2, '') | ||
if not display then | local title = argDefault('title') | ||
if | 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 = | 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.
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