Module:HackerNewsUtil: Difference between revisions
From Rest of What I Know
No edit summary |
No edit summary |
||
| Line 131: | Line 131: | ||
local function addBullet() meta:tag('span'):wikitext('•'):css('opacity','0.6') end | local function addBullet() meta:tag('span'):wikitext('•'):css('opacity','0.6') end | ||
local hasContent = false | local hasContent = false | ||
if author and author ~= '' then | |||
meta:wikitext(mw.text.nowiki(author)) | |||
hasContent = true | |||
end | |||
if dateHuman and dateHuman ~= '' then | if dateHuman and dateHuman ~= '' then | ||
if hasContent then addBullet() end | |||
meta:tag('time'):attr('datetime', dateISO or ''):wikitext(dateHuman) | meta:tag('time'):attr('datetime', dateISO or ''):wikitext(dateHuman) | ||
hasContent = true | hasContent = true | ||
Revision as of 23:45, 20 October 2025
Documentation for this module may be created at Module:HackerNewsUtil/doc
local p = {}
local HN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" height="18" viewBox="4 4 188 188" width="18"><path d="m4 4h188v188h-188z" fill="#f60"/><path d="m73.2521756 45.01 22.7478244 47.39130083 22.7478244-47.39130083h19.56569631l-34.32352071 64.48661468v41.49338532h-15.98v-41.49338532l-34.32352071-64.48661468z" fill="#fff"/></svg>'
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 host, id = url:match('^https?://([^/]+)/item%?id=(%d+)')
if id then
return { id = id, site = host }
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')
local paras, 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(id, site)
if id and site then
return string.format('Permalink: HN • %s • %s', site, id)
elseif id then
return 'Permalink: HN • ' .. id
else
return 'Permalink'
end
end
local function gen_refname(id, url)
if id and id ~= '' then
return 'hn-' .. id
end
return 'hn-' .. 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 siteArg = trim(args.site)
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 isComment = trim(args.comment) == 'yes'
local refname = trim(args.refname)
local noreference = (trim(args.noreference) == 'yes') or (trim(args.ref) == 'no')
local parsed = parse_from_url(url or '')
local id = parsed.id
local site = siteArg or parsed.site or 'news.ycombinator.com'
-- Fallback permalink if url omitted but id present
if (not url or url == '') and id then
url = 'https://news.ycombinator.com/item?id=' .. id
end
-- Auto author URL if not provided and single author
if author and author ~= '' and (not authorURL or authorURL == '') and not author:find('|') then
local enc = mw.uri.encode(author, 'QUERY')
authorURL = 'https://news.ycombinator.com/user?id=' .. enc
end
local h = mw.html.create('div')
:addClass('mw-hn')
:cssText('border:1px solid #e2e8f0;border-radius:8px;padding:12px 14px;margin:8px 0;background:#fff;')
-- Header with icon via CSS data-URI
local header = h:tag('div'):addClass('mw-hn-header')
:cssText('font-size:0.9em;color:#475569;margin-bottom:6px;display:flex;gap:8px;align-items:center;')
header:tag('span')
:addClass('mw-hn-logo')
:attr('aria-hidden', 'true')
header:tag('span'):wikitext('Hacker News')
-- Title
if title and title ~= '' then
local titleDiv = h:tag('div')
:addClass('mw-hn-title')
:cssText('font-weight:600;margin:2px 0 6px 0;')
if isComment then
titleDiv:tag('span')
:cssText('font-weight:normal;font-style:italic;')
:wikitext('Comment on')
titleDiv:wikitext(' ' .. title)
else
titleDiv:wikitext(title)
end
end
-- Body text (optional)
if text and text ~= '' then
local bq = h:tag('blockquote')
:addClass('mw-hn-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-hn-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
local hasContent = false
if author and author ~= '' then
meta:wikitext(mw.text.nowiki(author))
hasContent = true
end
if dateHuman and dateHuman ~= '' then
if hasContent then addBullet() end
meta:tag('time'):attr('datetime', dateISO or ''):wikitext(dateHuman)
hasContent = true
end
if score and score ~= '' then
if hasContent then addBullet() end
meta:wikitext(tostring(score) .. ' points')
hasContent = true
end
if comments and comments ~= '' then
if hasContent then addBullet() end
meta:wikitext(tostring(comments) .. ' comments')
hasContent = true
end
-- Footnote reference (permalink)
if url and url ~= '' and not noreference then
local name = refname or gen_refname(id, url)
-- Build reference text with author if provided
local ref_parts = {}
if author and author ~= '' then
local parts = mw.text.split(author, '%s*|%s*')
local author_links = {}
for i, authorName in ipairs(parts) do
local authorUrl = authorURL
if not authorUrl or authorUrl == '' or #parts > 1 then
local enc = mw.uri.encode(authorName, 'QUERY')
authorUrl = 'https://news.ycombinator.com/user?id=' .. enc
end
table.insert(author_links, string.format('[%s %s]', authorUrl, mw.text.nowiki(authorName)))
end
table.insert(ref_parts, table.concat(author_links, ', '))
table.insert(ref_parts, ' on ')
end
table.insert(ref_parts, string.format('[%s %s]', url, anchor_text(id, site)))
local text_ref = table.concat(ref_parts, '')
local ref_markup = frame:extensionTag('ref', text_ref, { name = name })
meta:wikitext(' ' .. ref_markup)
end
return tostring(h)
end
return p
