Module:RedditUtil: Difference between revisions
From Rest of What I Know
Created page with "local p = {} local function trim(s) if type(s) ~= 'string' then return nil end return (s:gsub('^%s+', ''):gsub('%s+$', '')) end local function parse_from_url(url) if type(url) ~= 'string' then return {} end local u = url -- normalize common host variants -- supports old.reddit.com / www.reddit.com / reddit.com local sub, id = u:match('^https?://[^/]*reddit%.com/r/([A-Za-z0-9_]+)/comments/([A-Za-z0-9]+)/') if sub and id then return {subreddit = sub,..." |
No edit summary |
||
| (2 intermediate revisions by the same user not shown) | |||
| Line 8: | Line 8: | ||
local function parse_from_url(url) | local function parse_from_url(url) | ||
if type(url) ~= 'string' then return {} end | if type(url) ~= 'string' then return {} end | ||
local sub, id = url:match('^https?://[^/]*reddit%.com/r/([A-Za-z0-9_]+)/comments/([A-Za-z0-9]+)/') | |||
local sub, id = | |||
if sub and id then | if sub and id then | ||
return {subreddit = sub, id = id} | return {subreddit = sub, id = id} | ||
end | end | ||
id = url:match('^https?://[^/]*reddit%.com/comments/([A-Za-z0-9]+)/') | |||
id = | |||
if id then | if id then | ||
return {id = id} | return {id = id} | ||
end | end | ||
id = url:match('^https?://[^/]*redd%.it/([A-Za-z0-9]+)') | |||
id = | |||
if id then | if id then | ||
return {id = id} | return {id = id} | ||
end | end | ||
return {} | return {} | ||
end | |||
-- Render plain text with paragraphs preserved. | |||
-- Two or more newlines => new <p>. Single newline => <br>. | |||
local function render_paragraph_text(parent, s) | |||
if type(s) ~= 'string' or s == '' then return end | |||
s = s:gsub('\r\n', '\n') -- normalize | |||
local paras = {} | |||
local i = 1 | |||
while true do | |||
local a, b = s:find('\n\n+', i) | |||
if not a then | |||
table.insert(paras, s:sub(i)) | |||
break | |||
end | |||
table.insert(paras, s:sub(i, a - 1)) | |||
i = b + 1 | |||
end | |||
for _, para in ipairs(paras) do | |||
local pnode = parent:tag('p') | |||
local first = true | |||
for line in (para .. '\n'):gmatch('(.-)\n') do | |||
if not first then pnode:tag('br') end | |||
pnode:wikitext(mw.text.nowiki(line)) | |||
first = false | |||
end | |||
end | |||
end | |||
local function anchor_text(subreddit, id) | |||
if subreddit and id then | |||
return string.format('Permalink: r/%s • %s', subreddit, id) | |||
elseif id then | |||
return 'Permalink: ' .. id | |||
else | |||
return 'Permalink' | |||
end | |||
end | |||
local function gen_refname(id, url) | |||
if id and id ~= '' then | |||
return 'reddit-' .. id | |||
end | |||
return 'reddit-' .. mw.hash.hashValue('md5', url or tostring(mw.title.getCurrentTitle())) | |||
end | end | ||
function p.render(frame) | function p.render(frame) | ||
local args = frame:getParent() and frame:getParent().args or frame.args | local args = frame:getParent() and frame:getParent().args or frame.args | ||
local url | local url = trim(args.url) | ||
local author | local author = trim(args.author) | ||
local authorURL = trim(args.author_url) | local authorURL = trim(args.author_url) | ||
local title | local title = trim(args.title) | ||
local text | local text = trim(args.text) | ||
local dateHuman = trim(args.date) | local dateHuman = trim(args.date) | ||
local dateISO | local dateISO = trim(args.datetime) or dateHuman | ||
local score | local score = trim(args.score) | ||
local comments = trim(args. | local comments = trim(args.comments) | ||
local subreddit = trim(args.subreddit) | |||
local refname = trim(args.refname) | |||
local noreference = (trim(args.noreference) == 'yes') or (trim(args.ref) == 'no') | |||
local parsed = parse_from_url(url or '') | local parsed = parse_from_url(url or '') | ||
if not subreddit or subreddit == '' then | |||
subreddit = parsed.subreddit | |||
end | |||
local id = parsed.id | local id = parsed.id | ||
| Line 48: | Line 93: | ||
:cssText('border:1px solid #e2e8f0;border-radius:8px;padding:12px 14px;margin:8px 0;background:#fff;') | :cssText('border:1px solid #e2e8f0;border-radius:8px;padding:12px 14px;margin:8px 0;background:#fff;') | ||
-- Header | -- Header | ||
local header = h:tag('div'):addClass('mw-reddit-header') | local header = h:tag('div'):addClass('mw-reddit-header') | ||
:cssText('font-size:0.9em;color:#475569;margin-bottom:6px;display:flex;gap:8px;align-items:center;') | :cssText('font-size:0.9em;color:#475569;margin-bottom:6px;display:flex;gap:8px;align-items:center;') | ||
header:tag('span'):wikitext('Reddit') | header:tag('span'):wikitext('Reddit') | ||
if subreddit then | if subreddit then | ||
| Line 58: | Line 102: | ||
end | end | ||
-- Title | -- Title | ||
if title and title ~= '' then | if title and title ~= '' then | ||
h:tag('div') | h:tag('div') | ||
| Line 68: | Line 112: | ||
-- Body text (optional) | -- Body text (optional) | ||
if text and text ~= '' then | if text and text ~= '' then | ||
h:tag('blockquote') | local bq = h:tag('blockquote') | ||
:addClass('mw-reddit-text') | :addClass('mw-reddit-text') | ||
:cssText('margin:6px 0 10px 0;padding:0 0 0 12px;border-left:3px solid #e2e8f0;color:#0f172a;') | :cssText('margin:6px 0 10px 0;padding:0 0 0 12px;border-left:3px solid #e2e8f0;color:#0f172a;') | ||
render_paragraph_text(bq, text) | |||
end | end | ||
-- Meta line | -- Meta line | ||
local meta = h:tag('div'):addClass('mw-reddit-meta') | local meta = h:tag('div'):addClass('mw-reddit-meta') | ||
:cssText('font-size:0.85em;color:#475569;display:flex;flex-wrap:wrap;gap:8px;align-items:center;') | :cssText('font-size:0.85em;color:#475569;display:flex;flex-wrap:wrap;gap:8px;align-items:center;') | ||
| Line 92: | Line 136: | ||
if dateHuman and dateHuman ~= '' then | if dateHuman and dateHuman ~= '' then | ||
if author and author ~= '' then addBullet() end | if author and author ~= '' then addBullet() end | ||
meta:tag('time'):attr('datetime', dateISO or ''):wikitext(dateHuman) | |||
end | end | ||
| Line 105: | Line 149: | ||
end | end | ||
-- | -- Footnote reference (permalink) | ||
if url and url ~= '' then | if url and url ~= '' and not noreference then | ||
local | local name = refname or gen_refname(id, url) | ||
local text_ref = string.format('[%s %s]', url, anchor_text(subreddit, id)) | |||
local | local ref_markup = frame:extensionTag('ref', text_ref, { name = name }) | ||
meta:wikitext(' ' .. ref_markup) | |||
end | end | ||
Latest revision as of 03:18, 15 September 2025
Documentation for this module may be created at Module:RedditUtil/doc
local p = {}
local function trim(s)
if type(s) ~= 'string' then return nil end
return (s:gsub('^%s+', ''):gsub('%s+$', ''))
end
local function parse_from_url(url)
if type(url) ~= 'string' then return {} end
local sub, id = url:match('^https?://[^/]*reddit%.com/r/([A-Za-z0-9_]+)/comments/([A-Za-z0-9]+)/')
if sub and id then
return {subreddit = sub, id = id}
end
id = url:match('^https?://[^/]*reddit%.com/comments/([A-Za-z0-9]+)/')
if id then
return {id = id}
end
id = url:match('^https?://[^/]*redd%.it/([A-Za-z0-9]+)')
if id then
return {id = id}
end
return {}
end
-- Render plain text with paragraphs preserved.
-- Two or more newlines => new <p>. Single newline => <br>.
local function render_paragraph_text(parent, s)
if type(s) ~= 'string' or s == '' then return end
s = s:gsub('\r\n', '\n') -- normalize
local paras = {}
local i = 1
while true do
local a, b = s:find('\n\n+', i)
if not a then
table.insert(paras, s:sub(i))
break
end
table.insert(paras, s:sub(i, a - 1))
i = b + 1
end
for _, para in ipairs(paras) do
local pnode = parent:tag('p')
local first = true
for line in (para .. '\n'):gmatch('(.-)\n') do
if not first then pnode:tag('br') end
pnode:wikitext(mw.text.nowiki(line))
first = false
end
end
end
local function anchor_text(subreddit, id)
if subreddit and id then
return string.format('Permalink: r/%s • %s', subreddit, id)
elseif id then
return 'Permalink: ' .. id
else
return 'Permalink'
end
end
local function gen_refname(id, url)
if id and id ~= '' then
return 'reddit-' .. id
end
return 'reddit-' .. mw.hash.hashValue('md5', url or tostring(mw.title.getCurrentTitle()))
end
function p.render(frame)
local args = frame:getParent() and frame:getParent().args or frame.args
local url = trim(args.url)
local author = trim(args.author)
local authorURL = trim(args.author_url)
local title = trim(args.title)
local text = trim(args.text)
local dateHuman = trim(args.date)
local dateISO = trim(args.datetime) or dateHuman
local score = trim(args.score)
local comments = trim(args.comments)
local subreddit = trim(args.subreddit)
local refname = trim(args.refname)
local noreference = (trim(args.noreference) == 'yes') or (trim(args.ref) == 'no')
local parsed = parse_from_url(url or '')
if not subreddit or subreddit == '' then
subreddit = parsed.subreddit
end
local id = parsed.id
local h = mw.html.create('div')
:addClass('mw-reddit')
:cssText('border:1px solid #e2e8f0;border-radius:8px;padding:12px 14px;margin:8px 0;background:#fff;')
-- Header
local header = h:tag('div'):addClass('mw-reddit-header')
:cssText('font-size:0.9em;color:#475569;margin-bottom:6px;display:flex;gap:8px;align-items:center;')
header:tag('span'):wikitext('Reddit')
if subreddit then
header:tag('span'):wikitext('•'):css('opacity','0.6')
header:tag('span'):wikitext('r/' .. subreddit)
end
-- Title
if title and title ~= '' then
h:tag('div')
:addClass('mw-reddit-title')
:cssText('font-weight:600;margin:2px 0 6px 0;')
:wikitext(title)
end
-- Body text (optional)
if text and text ~= '' then
local bq = h:tag('blockquote')
:addClass('mw-reddit-text')
:cssText('margin:6px 0 10px 0;padding:0 0 0 12px;border-left:3px solid #e2e8f0;color:#0f172a;')
render_paragraph_text(bq, text)
end
-- Meta line
local meta = h:tag('div'):addClass('mw-reddit-meta')
:cssText('font-size:0.85em;color:#475569;display:flex;flex-wrap:wrap;gap:8px;align-items:center;')
local function addBullet()
meta:tag('span'):wikitext('•'):css('opacity','0.6')
end
if author and author ~= '' then
if authorURL and authorURL ~= '' then
meta:wikitext(string.format('[[%s|%s]]', authorURL, author))
else
meta:wikitext(author)
end
end
if dateHuman and dateHuman ~= '' then
if author and author ~= '' then addBullet() end
meta:tag('time'):attr('datetime', dateISO or ''):wikitext(dateHuman)
end
if score and score ~= '' then
if (author and author ~= '') or (dateHuman and dateHuman ~= '') then addBullet() end
meta:wikitext(tostring(score) .. ' points')
end
if comments and comments ~= '' then
if (author and author ~= '') or (dateHuman and dateHuman ~= '') or (score and score ~= '') then addBullet() end
meta:wikitext(tostring(comments) .. ' comments')
end
-- Footnote reference (permalink)
if url and url ~= '' and not noreference then
local name = refname or gen_refname(id, url)
local text_ref = string.format('[%s %s]', url, anchor_text(subreddit, id))
local ref_markup = frame:extensionTag('ref', text_ref, { name = name })
meta:wikitext(' ' .. ref_markup)
end
return tostring(h)
end
return p
