| 12 | 1 local Luan = require "luan:Luan.luan" | 
|  | 2 local error = Luan.error | 
|  | 3 local type = Luan.type or error() | 
|  | 4 local ipairs = Luan.ipairs or error() | 
|  | 5 local stringify = Luan.stringify or error() | 
| 13 | 6 local Io = require "luan:Io.luan" | 
|  | 7 local output_of = Io.output_of or error() | 
| 12 | 8 local Parsers = require "luan:Parsers.luan" | 
|  | 9 local bbcode_parse = Parsers.bbcode_parse or error() | 
|  | 10 local Html = require "luan:Html.luan" | 
|  | 11 local html_encode = Html.encode or error() | 
| 21 | 12 local html_parse = Html.parse or error() | 
| 12 | 13 local Table = require "luan:Table.luan" | 
|  | 14 local is_list = Table.is_list or error() | 
| 21 | 15 local concat = Table.concat or error() | 
| 13 | 16 local String = require "luan:String.luan" | 
|  | 17 local gsub = String.gsub or error() | 
| 21 | 18 local matches = String.matches or error() | 
| 23 | 19 local match = String.match or error() | 
| 12 | 20 local User = require "site:/lib/User.luan" | 
| 13 | 21 local Shared = require "site:/lib/Shared.luan" | 
|  | 22 local list_to_set = Shared.list_to_set or error() | 
| 20 | 23 local to_list = Shared.to_list or error() | 
| 12 | 24 local Logging = require "luan:logging/Logging.luan" | 
|  | 25 local logger = Logging.logger "Bbcode" | 
|  | 26 | 
|  | 27 | 
|  | 28 local Bbcode = {} | 
|  | 29 | 
|  | 30 local to_html | 
|  | 31 local html = {} | 
|  | 32 | 
| 20 | 33 function html.b(bbcode,options) | 
|  | 34 	%><b><% to_html(bbcode.contents,options) %></b><% | 
|  | 35 end | 
|  | 36 | 
|  | 37 function html.i(bbcode,options) | 
|  | 38 	%><i><% to_html(bbcode.contents,options) %></i><% | 
|  | 39 end | 
|  | 40 | 
|  | 41 function html.u(bbcode,options) | 
|  | 42 	%><u><% to_html(bbcode.contents,options) %></u><% | 
| 12 | 43 end | 
|  | 44 | 
| 20 | 45 function html.s(bbcode,options) | 
|  | 46 	%><s><% to_html(bbcode.contents,options) %></s><% | 
| 12 | 47 end | 
|  | 48 | 
| 20 | 49 function html.sup(bbcode,options) | 
|  | 50 	%><sup><% to_html(bbcode.contents,options) %></sup><% | 
| 12 | 51 end | 
|  | 52 | 
| 20 | 53 function html.brackets(bbcode,options) | 
|  | 54 	%>[<% to_html(bbcode.contents,options) %>]<% | 
|  | 55 end | 
|  | 56 | 
|  | 57 function html.url(bbcode,options) | 
| 12 | 58 	local url = bbcode.param | 
|  | 59 	if url == nil then | 
|  | 60 		url = html_encode(bbcode.contents) | 
|  | 61 		%><a href="<%=url%>"><%=url%></a><% | 
|  | 62 	else | 
|  | 63 		url = html_encode(url) | 
| 20 | 64 		%><a href="<%=url%>"><% to_html(bbcode.contents,options) %></a><% | 
| 12 | 65 	end | 
|  | 66 end | 
|  | 67 | 
| 20 | 68 function html.code(bbcode,options) | 
|  | 69 	local s = gsub(bbcode.contents,[[^\n]],"") | 
|  | 70 	%><code><%= html_encode(s) %></code><% | 
|  | 71 	options.strip_newline = true | 
| 12 | 72 end | 
|  | 73 | 
| 20 | 74 function html.img(bbcode,options) | 
| 12 | 75 	%><img src="<%= html_encode(bbcode.contents) %>"><% | 
|  | 76 end | 
|  | 77 | 
| 20 | 78 function html.color(bbcode,options) | 
|  | 79 	%><span style="color:<%=bbcode.param%>"><% to_html(bbcode.contents,options) %></span><% | 
| 12 | 80 end | 
|  | 81 | 
| 20 | 82 function html.size(bbcode,options) | 
| 23 | 83 	%><span style="font-size:<%=bbcode.param%>"><% to_html(bbcode.contents,options) %></span><% | 
| 12 | 84 end | 
|  | 85 | 
| 20 | 86 function html.quote(bbcode,options) | 
| 12 | 87 	%><blockquote><% | 
|  | 88 	local user_name = bbcode.param | 
|  | 89 	if user_name ~= nil then | 
|  | 90 		local user = User.get_by_name(user_name) | 
|  | 91 		if user == nil then | 
|  | 92 			%><%= user_name %> wrote:<% | 
|  | 93 		else | 
|  | 94 			%><a href="/user_something"><%= user_name %></a> wrote:<% | 
|  | 95 		end | 
| 20 | 96 	else | 
|  | 97 		options.strip_newline = true | 
| 12 | 98 	end | 
| 20 | 99 	to_html(bbcode.contents,options) | 
| 12 | 100 	%></blockquote><% | 
| 20 | 101 	options.strip_newline = true | 
| 12 | 102 end | 
|  | 103 | 
| 23 | 104 local youtube_ptn1 = [[https://youtu.be/([a-zA-Z0-9_-]+)(?:\?t=([0-9]+))?]] | 
|  | 105 local youtube_ptn2 = [[https://www.youtube.com/watch\?v=([a-zA-Z0-9_-]+)(?:&t=([0-9]+)s)?]] | 
|  | 106 local bitchute_ptn = [[https://www.bitchute.com/video/([a-zA-Z0-9]+)/]] | 
|  | 107 | 
| 20 | 108 function html.video(bbcode,options) | 
| 23 | 109 	local url = bbcode.contents | 
|  | 110 	local id, start = match(url,youtube_ptn1) | 
|  | 111 	if id == nil then | 
|  | 112 		id, start = match(url,youtube_ptn2) | 
|  | 113 	end | 
|  | 114 	if id ~= nil then | 
|  | 115 		%><iframe width="560" height="315" src="https://www.youtube.com/embed/<%=id%><% | 
| 12 | 116 		if start ~= nil then | 
|  | 117 			%>?start=<%=start%><% | 
|  | 118 		end | 
|  | 119 		%>" frameborder="0" allowfullscreen></iframe><% | 
| 23 | 120 		return | 
| 12 | 121 	end | 
| 23 | 122 	id = match(url,bitchute_ptn) | 
|  | 123 	if id ~= nil then | 
|  | 124 		%><iframe width="560" height="315" scrolling="no" frameborder="0" style="border: none;" src="https://www.bitchute.com/embed/<%=id%>/"></iframe><% | 
|  | 125 		return | 
|  | 126 	end | 
|  | 127 	url = html_encode(url) | 
|  | 128 	%><a href="<%=url%>"><%=url%></a><% | 
| 12 | 129 end | 
|  | 130 | 
| 20 | 131 local function list_to_html(bbcode,options) | 
|  | 132 	local list = to_list(bbcode.contents) | 
|  | 133 	for _, item in ipairs(list) do | 
|  | 134 		if type(item) == "table" and item.name == "li" then | 
|  | 135 			%><li><% to_html(item.contents,options) %></li><% | 
|  | 136 		end | 
|  | 137 	end | 
|  | 138 	options.strip_newline = true | 
|  | 139 end | 
|  | 140 | 
|  | 141 function html.ul(bbcode,options) | 
|  | 142 	%><ul><% | 
|  | 143 	list_to_html(bbcode,options) | 
|  | 144 	%></ul><% | 
|  | 145 end | 
|  | 146 | 
|  | 147 function html.ol(bbcode,options) | 
|  | 148 	%><ol><% | 
|  | 149 	list_to_html(bbcode,options) | 
|  | 150 	%></ol><% | 
|  | 151 end | 
|  | 152 | 
|  | 153 function to_html(bbcode,options) | 
|  | 154 	if options.strip_newline then | 
|  | 155 		if type(bbcode) == "string" then | 
|  | 156 			bbcode = gsub(bbcode,[[^\n]],"") | 
|  | 157 		end | 
|  | 158 		options.strip_newline = false | 
|  | 159 	end | 
| 12 | 160 	if type(bbcode) == "string" then | 
|  | 161 		%><%= html_encode(bbcode) %><% | 
|  | 162 	else | 
|  | 163 		type(bbcode) == "table" or error() | 
|  | 164 		if is_list(bbcode) then | 
|  | 165 			for _, v in ipairs(bbcode) do | 
| 20 | 166 				to_html(v,options) | 
| 12 | 167 			end | 
|  | 168 		else | 
|  | 169 			local fn = html[bbcode.name] or error(bbcode.name.." not handled") | 
| 20 | 170 			fn(bbcode,options) | 
| 12 | 171 		end | 
|  | 172 	end | 
|  | 173 end | 
|  | 174 | 
|  | 175 function Bbcode.to_html(bbcode) | 
|  | 176 	bbcode = bbcode_parse(bbcode) | 
| 20 | 177 	%><div message><% | 
|  | 178 	to_html(bbcode,{strip_newline=false}) | 
|  | 179 	%></div><% | 
| 12 | 180 end | 
|  | 181 | 
| 13 | 182 | 
|  | 183 local doesnt_nest = list_to_set{ | 
|  | 184 	"url" | 
|  | 185 	"code" | 
|  | 186 	"img" | 
|  | 187 	"video" | 
|  | 188 } | 
|  | 189 | 
|  | 190 local function preprocess(bbcode) | 
|  | 191 	if type(bbcode) == "string" then | 
|  | 192 		bbcode = gsub( bbcode, [[(^|\s)(https?://\S+)]], "$1[url]$2[/url]" ) | 
|  | 193 		%><%= bbcode %><% | 
|  | 194 	else | 
|  | 195 		type(bbcode) == "table" or error() | 
|  | 196 		if is_list(bbcode) then | 
|  | 197 			for _, v in ipairs(bbcode) do | 
|  | 198 				preprocess(v) | 
|  | 199 			end | 
|  | 200 		else | 
|  | 201 			local name = bbcode.name | 
|  | 202 			local param = bbcode.param | 
|  | 203 			%>[<%=name%><% | 
|  | 204 			if param ~= nil then | 
|  | 205 				%>=<%=param%><% | 
|  | 206 			end | 
|  | 207 			%>]<% | 
|  | 208 			if doesnt_nest[name] then | 
|  | 209 				%><%=bbcode.contents%><% | 
|  | 210 			else | 
|  | 211 				preprocess(bbcode.contents) | 
|  | 212 			end | 
| 20 | 213 			if name == "code" and param ~= nil then | 
|  | 214 				%>[/<%=name%>=<%=param%>]<% | 
|  | 215 			else | 
|  | 216 				%>[/<%=name%>]<% | 
|  | 217 			end | 
| 13 | 218 		end | 
|  | 219 	end | 
|  | 220 end | 
|  | 221 | 
|  | 222 function Bbcode.preprocess(bbcode) | 
|  | 223 	bbcode = bbcode_parse(bbcode) | 
|  | 224 	return output_of(function() | 
|  | 225 		preprocess(bbcode) | 
|  | 226 	end) | 
|  | 227 end | 
|  | 228 | 
| 21 | 229 function Bbcode.remove_html(text) | 
|  | 230 	local ends_with_newline = matches(text,[[\n$]]) | 
|  | 231 	local t = {} | 
|  | 232 	local html = html_parse(text) | 
|  | 233 	local is_first = true | 
|  | 234 	for _, v in ipairs(html) do | 
|  | 235 		if type(v) == "string" then | 
|  | 236 			t[#t+1] = v | 
|  | 237 		else | 
|  | 238 			local name = v.name | 
|  | 239 			if name == "div" then | 
|  | 240 				if not is_first then | 
|  | 241 					t[#t+1] = "\n" | 
|  | 242 				end | 
|  | 243 			elseif name == "/div" or name == "br" then | 
|  | 244 				-- ignore | 
|  | 245 			else | 
|  | 246 				error("unexpected tag: "..name) | 
|  | 247 			end | 
|  | 248 		end | 
|  | 249 		is_first = false | 
|  | 250 	end | 
|  | 251 	if not ends_with_newline then | 
|  | 252 		t[#t+1] = "\n" | 
|  | 253 	end | 
|  | 254 	return concat(t) | 
|  | 255 end | 
|  | 256 | 
|  | 257 | 
| 12 | 258 return Bbcode |