Mercurial Hosting > freedit
diff src/bbcode/Bbcode.luan @ 44:96f0c3d65698
add /bbcode
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 10 Nov 2022 23:18:58 -0700 |
parents | src/lib/Bbcode.luan@298c71e0c854 |
children | 2d4f00755092 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bbcode/Bbcode.luan Thu Nov 10 23:18:58 2022 -0700 @@ -0,0 +1,338 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local type = Luan.type or error() +local ipairs = Luan.ipairs or error() +local pairs = Luan.pairs or error() +local stringify = Luan.stringify or error() +local Io = require "luan:Io.luan" +local output_of = Io.output_of or error() +local Parsers = require "luan:Parsers.luan" +local bbcode_parse = Parsers.bbcode_parse or error() +local Html = require "luan:Html.luan" +local html_encode = Html.encode or error() +local html_parse = Html.parse or error() +local Table = require "luan:Table.luan" +local is_list = Table.is_list or error() +local concat = Table.concat or error() +local String = require "luan:String.luan" +local regex = String.regex or error() +local ends_with = String.ends_with or error() +local User = require "site:/lib/User.luan" +local Shared = require "site:/lib/Shared.luan" +local list_to_set = Shared.list_to_set or error() +local to_list = Shared.to_list or error() +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "Bbcode" + + +local Bbcode = {} + +local starting_cr_regex = regex[[^\n]] + +local to_html +local html = {} + +function html.b(bbcode,options) + %><b><% to_html(bbcode.contents,options) %></b><% +end + +function html.i(bbcode,options) + %><i><% to_html(bbcode.contents,options) %></i><% +end + +function html.u(bbcode,options) + %><u><% to_html(bbcode.contents,options) %></u><% +end + +function html.s(bbcode,options) + %><s><% to_html(bbcode.contents,options) %></s><% +end + +function html.sup(bbcode,options) + %><sup><% to_html(bbcode.contents,options) %></sup><% +end + +function html.brackets(bbcode,options) + %>[<% to_html(bbcode.contents,options) %>]<% +end + +function html.url(bbcode,options) + local url = bbcode.param + if url == nil then + url = html_encode(bbcode.contents) + %><a href="<%=url%>"><%=url%></a><% + else + url = html_encode(url) + %><a href="<%=url%>"><% to_html(bbcode.contents,options) %></a><% + end +end + +function html.code(bbcode,options) + local s = starting_cr_regex.gsub(bbcode.contents,"") + %><code><%= html_encode(s) %></code><% + options.strip_newline = true +end + +function html.img(bbcode,options) + %><img src="<%= html_encode(bbcode.contents) %>"><% +end + +function html.color(bbcode,options) + %><span style="color:<%=bbcode.param%>"><% to_html(bbcode.contents,options) %></span><% +end + +function html.size(bbcode,options) + %><span style="font-size:<%=bbcode.param%>"><% to_html(bbcode.contents,options) %></span><% +end + +function html.quote(bbcode,options) + %><blockquote><% + local user_name = bbcode.param + if user_name ~= nil then + local user = User.get_by_name(user_name) + if user == nil then + %><%= user_name %> wrote:<% + else + %><a href="/user_something"><%= user_name %></a> wrote:<% + end + else + options.strip_newline = true + end + to_html(bbcode.contents,options) + %></blockquote><% + options.strip_newline = true +end + +local function video_iframe(url) + %><iframe width="560" height="315" frameborder="0" allowfullscreen src="<%=url%>"></iframe><% +end + +local video_handlers = {} +do + local ptn1 = regex[[^\Qhttps://youtu.be/\E([a-zA-Z0-9_-]+)(?:\?t=([0-9]+))?]] + local ptn2 = regex[[^\Qhttps://www.youtube.com/watch?v=\E([a-zA-Z0-9_-]+)(?:&t=([0-9]+)s)?]] + function video_handlers.youtube(url) + local id, start = ptn1.match(url) + if id == nil then + id, start = ptn2.match(url) + end + if id == nil then + return false + end + url = "https://www.youtube.com/embed/"..id + if start ~= nil then + url = url.."?start="..start + end + video_iframe(url) + return true + end +end +do + local ptn = regex[[^\Qhttps://rumble.com/embed/\E[a-z0-9]+/\?pub=[a-z0-9]+]] + function video_handlers.rumble(url) + if not ptn.matches(url) then + return false + end + video_iframe(url) + return true + end +end +do + local ptn = regex[[^\Qhttps://www.bitchute.com/video/\E([a-zA-Z0-9]+)/]] + function video_handlers.bitchute(url) + local id = ptn.match(url) + if id == nil then + return false + end + url = "https://www.bitchute.com/embed/"..id.."/" + video_iframe(url) + return true + end +end +do + local ptn = regex[[^\Qhttps://vimeo.com/\E([0-9]+)]] + function video_handlers.vimeo(url) + local id = ptn.match(url) + if id == nil then + return false + end + url = "https://player.vimeo.com/video/"..id + video_iframe(url) + return true + end +end +do + local ptn = regex[[^\Qhttps://dai.ly/\E([a-z0-9]+)]] + function video_handlers.dailymotion(url) + local id = ptn.match(url) + if id == nil then + return false + end + url = "https://www.dailymotion.com/embed/video/"..id + video_iframe(url) + return true + end +end +do + local ptn = regex[[^\Qhttps://www.tiktok.com/\E[^/]+/video/([0-9]+)]] + function video_handlers.tiktok(url) + local id = ptn.match(url) + if id == nil then + return false + end + %><blockquote class="tiktok-embed" data-video-id="<%=id%>" style="max-width: 560px; margin-left: 0;"><section></section></blockquote><% + %><script async src="https://www.tiktok.com/embed.js"></script><% + return true + end +end +do + local ptn = regex[[\.[a-zA-Z0-9]+$]] + function video_handlers.file(url) + if not ptn.matches(url) then + return false + end + %><video controls width="560"><source src="<%=html_encode(url)%>"></video><% + return true + end +end + +function html.video(bbcode,options) + local url = bbcode.contents + for _, handle in pairs(video_handlers) do + if handle(url) then return end + end + url = html_encode(url) + %><a href="<%=url%>"><%=url%></a><% +end + +local function list_to_html(bbcode,options) + local list = to_list(bbcode.contents) + for _, item in ipairs(list) do + if type(item) == "table" and item.name == "li" then + %><li><% to_html(item.contents,options) %></li><% + end + end + options.strip_newline = true +end + +function html.ul(bbcode,options) + %><ul><% + list_to_html(bbcode,options) + %></ul><% +end + +function html.ol(bbcode,options) + %><ol><% + list_to_html(bbcode,options) + %></ol><% +end + +function to_html(bbcode,options) + if options.strip_newline then + if type(bbcode) == "string" then + bbcode = starting_cr_regex.gsub(bbcode,"") + end + options.strip_newline = false + end + if type(bbcode) == "string" then + %><%= html_encode(bbcode) %><% + else + type(bbcode) == "table" or error() + if is_list(bbcode) then + for _, v in ipairs(bbcode) do + to_html(v,options) + end + else + local fn = html[bbcode.name] or error(bbcode.name.." not handled") + fn(bbcode,options) + end + end +end + +function Bbcode.to_html(bbcode) + bbcode = bbcode_parse(bbcode) + %><div message><% + to_html(bbcode,{strip_newline=false}) + %></div><% +end + + +local doesnt_nest = list_to_set{ + "url" + "code" + "img" + "video" +} + +local url_regex = regex[[(^|\s)(https?://\S+)]] + +local function preprocess(bbcode) + if type(bbcode) == "string" then + bbcode = url_regex.gsub( bbcode, "$1[url]$2[/url]" ) + %><%= bbcode %><% + else + type(bbcode) == "table" or error() + if is_list(bbcode) then + for _, v in ipairs(bbcode) do + preprocess(v) + end + else + local name = bbcode.name + local param = bbcode.param + %>[<%=name%><% + if param ~= nil then + %>=<%=param%><% + end + %>]<% + if doesnt_nest[name] then + %><%=bbcode.contents%><% + else + preprocess(bbcode.contents) + end + if name == "code" and param ~= nil then + %>[/<%=name%>=<%=param%>]<% + else + %>[/<%=name%>]<% + end + end + end +end + +-- url handling +function Bbcode.preprocess(bbcode) + bbcode = bbcode_parse(bbcode) + return output_of(function() + preprocess(bbcode) + end) +end + +function Bbcode.remove_html(text) + local ends_with_newline = ends_with(text,"\n") + local t = {} + local html = html_parse(text) + local is_first = true + for _, v in ipairs(html) do + if type(v) == "string" then + t[#t+1] = v + else + local name = v.name + if name == "div" then + if not is_first then + t[#t+1] = "\n" + end + elseif name == "/div" or name == "br" then + -- ignore + else + error("unexpected tag: "..name) + end + end + is_first = false + end + if not ends_with_newline then + t[#t+1] = "\n" + end + return concat(t) +end + + +return Bbcode