add bbcode support

This commit is contained in:
Lera Elvoé 2025-05-18 19:55:07 +03:00
parent 4039d6d299
commit 785eafd646
Signed by: yagich
SSH Key Fingerprint: SHA256:6xjGb6uA7lAVcULa7byPEN//rQ0wPoG+UzYVMfZnbvc
3 changed files with 69 additions and 2 deletions

62
lib/babycode.lua Normal file
View File

@ -0,0 +1,62 @@
local babycode = {}
local _escape_html = function(text)
return text:gsub("[&<>\"']", {
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;",
['"'] = "&quot;",
["'"] = "&#39;"
})
end
---renders babycode to html
---@param s string input babycode
---@param escape_html fun(s: string): string function that escapes html
function babycode.to_html(s, escape_html)
if not s or s == "" then return "" end
-- extract code blocks first and store them as placeholders
-- don't want to process bbcode embedded into a code block
local code_blocks = {}
local code_count = 0
local text = s:gsub("%[code%](.-)%[/code%]", function(code)
code_count = code_count + 1
code_blocks[code_count] = code
return "\1CODE:"..code_count.."\1"
end)
-- replace `[url=https://example.com]Example[/url] tags
text = text:gsub("%[url=([^%]]+)%](.-)%[/url%]", function(url, label)
return '<a href="'..escape_html(url)..'">'..escape_html(label)..'</a>'
end)
-- replace `[url]https://example.com[/url] tags
text = text:gsub("%[url%]([^%]]+)%[/url%]", function(url)
return '<a href="'..escape_html(url)..'">'..escape_html(url)..'</a>'
end)
-- bold, italics, strikethrough
text = text:gsub("%[b%](.-)%[/b%]", "<strong>%1</strong>")
text = text:gsub("%[i%](.-)%[/i%]", "<em>%1</em>")
text = text:gsub("%[s%](.-)%[/s%]", "<del>%1</del>")
-- replace loose links
text = text:gsub("(https?://[%w-_%.%?%.:/%+=&~%@#%%]+[%w-/])", function(url)
if not text:find('<a[^>]*>'..url..'</a>') then
return '<a href="'..escape_html(url)..'">'..escape_html(url)..'</a>'
end
return url
end)
-- replace code block placeholders back with their original contents
text = text:gsub("\1CODE:(%d+)\1", function(n)
return "<pre><code>"..code_blocks[tonumber(n)].."</code></pre>"
end)
-- finally, normalize newlines replace them with <br>
text = text:gsub("\r?\n\r?\n+", "<br>"):gsub("\r?\n", "<br>")
return text
end
return babycode

View File

@ -1,12 +1,15 @@
local util = {} local util = {}
local magick = require("magick") local magick = require("magick")
local db = require("lapis.db") local db = require("lapis.db")
local html_escape = require("lapis.html").escape
local Avatars = require("models").Avatars local Avatars = require("models").Avatars
local Users = require("models").Users local Users = require("models").Users
local Posts = require("models").Posts local Posts = require("models").Posts
local PostHistory = require("models").PostHistory local PostHistory = require("models").PostHistory
local babycode = require("lib.babycode")
util.TransientUser = { util.TransientUser = {
is_admin = function (self) is_admin = function (self)
return false return false
@ -109,10 +112,12 @@ function util.create_post(thread_id, user_id, content)
current_revision_id = db.NULL, current_revision_id = db.NULL,
}) })
local bb_content = babycode.to_html(content, html_escape)
local revision = PostHistory:create({ local revision = PostHistory:create({
post_id = post.id, post_id = post.id,
user_id = user_id, user_id = user_id,
content = content, content = bb_content,
is_initial_revision = true, is_initial_revision = true,
}) })

View File

@ -2,7 +2,7 @@
<div> <div>
<img src="<%= post.avatar_path or "/avatars/default.webp" %>"> <img src="<%= post.avatar_path or "/avatars/default.webp" %>">
<div><%= post.username %></div> <div><%= post.username %></div>
<div><p><%- require("lapis.html").escape(post.content):gsub("\n", "<br>") %></p></div> <div><p><%- post.content %></p></div>
</div> </div>
<% end %> <% end %>