add lists support to babycode
This commit is contained in:
parent
ea83a31b16
commit
e46883c3c1
@ -507,7 +507,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
|
|||||||
height: 150px;
|
height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul, ol {
|
||||||
margin: 10px 0 10px 30px;
|
margin: 10px 0 10px 30px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,82 @@
|
|||||||
local babycode = {}
|
local babycode = {}
|
||||||
|
|
||||||
|
local string_trim = require("lapis.util").trim
|
||||||
|
|
||||||
|
local function s_split(s, delimiter, max_matches, trim, allow_empty)
|
||||||
|
local result = {}
|
||||||
|
if s == "" then
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
trim = trim == nil and true or trim
|
||||||
|
local tr = function(subj)
|
||||||
|
if trim then return string_trim(subj) else return subj end
|
||||||
|
end
|
||||||
|
max_matches = max_matches or -1
|
||||||
|
allow_empty = allow_empty == nil and true or allow_empty
|
||||||
|
|
||||||
|
if delimiter == "" then
|
||||||
|
for i=1, #s do
|
||||||
|
local c = s:sub(i, 1)
|
||||||
|
if allow_empty or c ~= "" then
|
||||||
|
table.insert(result, c)
|
||||||
|
if max_matches > 0 and #result == max_matches then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local current_pos = 1
|
||||||
|
local delim_len = #delimiter
|
||||||
|
|
||||||
|
while true do
|
||||||
|
if max_matches > 0 and #result >= max_matches then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
---@diagnostic disable-next-line: param-type-mismatch
|
||||||
|
local start_pos, end_pos = s:find(delimiter, current_pos, true)
|
||||||
|
if not start_pos then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local substr = s:sub(current_pos, start_pos - 1)
|
||||||
|
if allow_empty or substr ~= "" then
|
||||||
|
table.insert(result, tr(substr))
|
||||||
|
end
|
||||||
|
current_pos = end_pos + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local substr = s:sub(current_pos)
|
||||||
|
if allow_empty or substr ~= "" then
|
||||||
|
table.insert(result, tr(substr))
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_list_items(list_body, escape_html)
|
||||||
|
list_body = list_body:gsub(" +%s*\r?\n", "<br>")
|
||||||
|
list_body = list_body:gsub("(%S)(\r?\n\r?\n)\r?\n*", "%1\1")
|
||||||
|
local list_items = s_split(list_body, "\1")
|
||||||
|
local lis = ""
|
||||||
|
for _, li in ipairs(list_items) do
|
||||||
|
local rendered = babycode.to_html(li, escape_html)
|
||||||
|
lis = lis .. "<li>" .. rendered .. "</li>"
|
||||||
|
end
|
||||||
|
return lis
|
||||||
|
end
|
||||||
|
|
||||||
---renders babycode to html
|
---renders babycode to html
|
||||||
---@param s string input babycode
|
---@param s string input babycode
|
||||||
---@param escape_html fun(s: string): string function that escapes html
|
---@param escape_html fun(s: string): string function that escapes html
|
||||||
function babycode.to_html(s, escape_html)
|
function babycode.to_html(s, escape_html)
|
||||||
if not s or s == "" then return "" end
|
if not s or s == "" then return "" end
|
||||||
-- extract code blocks first and store them as placeholders
|
local text = escape_html(s)
|
||||||
|
-- extract code blocks and store them as placeholders
|
||||||
-- don't want to process bbcode embedded into a code block
|
-- don't want to process bbcode embedded into a code block
|
||||||
local code_blocks = {}
|
local code_blocks = {}
|
||||||
local inline_codes = {}
|
local inline_codes = {}
|
||||||
s = escape_html(s)
|
text = text:gsub("%[code%](.-)%[/code%]", function(code)
|
||||||
local text = s:gsub("%[code%](.-)%[/code%]", function(code)
|
|
||||||
local is_inline = code:match("\n") == nil
|
local is_inline = code:match("\n") == nil
|
||||||
if is_inline then
|
if is_inline then
|
||||||
table.insert(inline_codes, code)
|
table.insert(inline_codes, code)
|
||||||
@ -23,10 +89,17 @@ function babycode.to_html(s, escape_html)
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
text = text:gsub(" %s?\r?\n", "<br>")
|
text = text:gsub("%[ul%](.-)%[/ul%]", function(list_body)
|
||||||
-- normalize newlines
|
return "<ul>" .. get_list_items(list_body, escape_html) .. "</ul>"
|
||||||
text = text:gsub("\r?\n\r?\n+", "<br>")
|
end)
|
||||||
|
text = text:gsub("%[ol%](.-)%[/ol%]", function(list_body)
|
||||||
|
return "<ol>" .. get_list_items(list_body, escape_html) .. "</ol>"
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- normalize newlines, attempt #4
|
||||||
|
text = text:gsub(" +%s*\r?\n", "<br>")
|
||||||
|
text = text:gsub("(%S)(\r?\n\r?\n)\r?\n*", "%1<br><br>")
|
||||||
|
|
||||||
local url_tags = {}
|
local url_tags = {}
|
||||||
-- replace `[url=https://example.com]Example[/url] tags
|
-- replace `[url=https://example.com]Example[/url] tags
|
||||||
text = text:gsub("%[url=([^%]]+)%](.-)%[/url%]", function(url, label)
|
text = text:gsub("%[url=([^%]]+)%](.-)%[/url%]", function(url, label)
|
||||||
@ -40,8 +113,6 @@ function babycode.to_html(s, escape_html)
|
|||||||
text = text:gsub("%[s%](.-)%[/s%]", "<del>%1</del>")
|
text = text:gsub("%[s%](.-)%[/s%]", "<del>%1</del>")
|
||||||
|
|
||||||
-- these can be nested, so replace open and closed separately
|
-- these can be nested, so replace open and closed separately
|
||||||
-- text = text:gsub("%[quote%]", "<blockquote>")
|
|
||||||
-- text = text:gsub("%[/quote%]", "</blockquote>")
|
|
||||||
text = text:gsub("%[(/?)quote%]", "<%1blockquote>")
|
text = text:gsub("%[(/?)quote%]", "<%1blockquote>")
|
||||||
|
|
||||||
-- replace loose links
|
-- replace loose links
|
||||||
|
@ -523,7 +523,7 @@ input[type="text"], input[type="password"], textarea, select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ul {
|
ul, ol {
|
||||||
margin: 10px 0 10px 30px;
|
margin: 10px 0 10px 30px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,27 @@
|
|||||||
<li>[i]<i>italic</i>[/i]</li>
|
<li>[i]<i>italic</i>[/i]</li>
|
||||||
<li>[s]<del>strikethrough</del>[/s]</li>
|
<li>[s]<del>strikethrough</del>[/s]</li>
|
||||||
<li>[url=https://example.com]<a href="https://example.com">labeled URL</a>[/url]</li>
|
<li>[url=https://example.com]<a href="https://example.com">labeled URL</a>[/url]</li>
|
||||||
|
<li>
|
||||||
|
[ul] and [ol] are unordered and ordered lists:
|
||||||
|
<details>
|
||||||
|
<summary>Show list example</summary>
|
||||||
|
<pre><span class="copy-code-container"><button type=button class="copy-code" value="[ul]
|
||||||
|
item 1
|
||||||
|
|
||||||
|
item 2
|
||||||
|
|
||||||
|
item 3
|
||||||
|
still item 3 (break line without inserting a new item by using two spaces at the end of a line)
|
||||||
|
[/ul]">Copy</button></span><code>[ul]
|
||||||
|
item 1
|
||||||
|
|
||||||
|
item 2
|
||||||
|
|
||||||
|
item 3
|
||||||
|
still item 3 (break line without inserting a new item by using two spaces at the end of a line)
|
||||||
|
[/ul]</code></pre>
|
||||||
|
</details>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
[code]with<br>line breaks[/code] will produce a code block:
|
[code]with<br>line breaks[/code] will produce a code block:
|
||||||
<details>
|
<details>
|
||||||
|
Loading…
Reference in New Issue
Block a user