Mercurial Hosting > freedit
view src/bbcode/Bbcode.luan @ 61:389e5d8e5f8a default tip
minor
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 06 Dec 2022 13:37:25 -0700 |
parents | cac477dd1f82 |
children |
line wrap: on
line source
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.sub(bbcode,options) %><sub><% to_html(bbcode.contents,options) %></sub><% 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) if bbcode.param == "inline" then %><code inline><%= html_encode(bbcode.contents) %></code><% else local s = starting_cr_regex.gsub(bbcode.contents,"") %><code><%= html_encode(s) %></code><% options.strip_newline = true end end function html.img(bbcode,options) %><img src="<%= html_encode(bbcode.contents) %>"<% if bbcode.param ~= nil then %> width="<%=bbcode.param%>"<% end %>><% 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_urls = { [[\.mp4$]] } local video_handlers = {} local function regex_video(s) video_urls[#video_urls+1] = s return regex(s) end do local ptn1 = regex_video[[^\Qhttps://youtu.be/\E([a-zA-Z0-9_-]+)(?:\?t=([0-9]+))?]] local ptn2 = regex_video[[^\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_video[[^\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_video[[^\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_video[[^\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_video[[^\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_video[[^\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 %><iframe allowfullscreen scrolling="no" width="325" height="720" src="https://www.tiktok.com/embed/<%=id%>"></iframe><% 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 local video_regex = regex(concat(video_urls,"|")) 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 == "item" then %><li><% to_html(item.contents,options) %></li><% end end options.strip_newline = true end function html.list(bbcode,options) local tag = bbcode.param == "1" and "ol" or "ul" %><<%=tag%>><% list_to_html(bbcode,options) %></<%=tag%>><% 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 from_bbcode><% 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 img_regex do local endings = { "jpg" "jpeg" "png" "gif" "svg" } local t = {} for _, ending in ipairs(endings) do t[#t+1] = [[\.]]..ending..[[$]] end img_regex = regex(concat(t,"|")) end local function preprocess(bbcode) if type(bbcode) == "string" then bbcode = url_regex.gsub( bbcode, function(prefix,url) if video_regex.matches(url) then return prefix.."[video]"..url.."[/video]" elseif img_regex.matches(url) then return prefix.."[img]"..url.."[/img]" else return prefix.."[url]"..url.."[/url]" end end ) %><%= 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