Mercurial Hosting > freedit
annotate src/bbcode/Bbcode.luan @ 57:169ac5fdb320
add change email
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Mon, 28 Nov 2022 23:47:19 -0700 |
| parents | cac477dd1f82 |
| children |
| rev | line source |
|---|---|
| 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() | |
| 28 | 5 local pairs = Luan.pairs or error() |
| 12 | 6 local stringify = Luan.stringify or error() |
| 13 | 7 local Io = require "luan:Io.luan" |
| 8 local output_of = Io.output_of or error() | |
| 12 | 9 local Parsers = require "luan:Parsers.luan" |
| 10 local bbcode_parse = Parsers.bbcode_parse or error() | |
| 11 local Html = require "luan:Html.luan" | |
| 12 local html_encode = Html.encode or error() | |
| 21 | 13 local html_parse = Html.parse or error() |
| 12 | 14 local Table = require "luan:Table.luan" |
| 15 local is_list = Table.is_list or error() | |
| 21 | 16 local concat = Table.concat or error() |
| 13 | 17 local String = require "luan:String.luan" |
| 29 | 18 local regex = String.regex or error() |
| 19 local ends_with = String.ends_with 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 | |
| 29 | 30 local starting_cr_regex = regex[[^\n]] |
| 31 | |
| 12 | 32 local to_html |
| 33 local html = {} | |
| 34 | |
| 20 | 35 function html.b(bbcode,options) |
| 36 %><b><% to_html(bbcode.contents,options) %></b><% | |
| 37 end | |
| 38 | |
| 39 function html.i(bbcode,options) | |
| 40 %><i><% to_html(bbcode.contents,options) %></i><% | |
| 41 end | |
| 42 | |
| 43 function html.u(bbcode,options) | |
| 44 %><u><% to_html(bbcode.contents,options) %></u><% | |
| 12 | 45 end |
| 46 | |
| 20 | 47 function html.s(bbcode,options) |
| 48 %><s><% to_html(bbcode.contents,options) %></s><% | |
| 12 | 49 end |
| 50 | |
| 20 | 51 function html.sup(bbcode,options) |
| 52 %><sup><% to_html(bbcode.contents,options) %></sup><% | |
| 12 | 53 end |
| 54 | |
| 45 | 55 function html.sub(bbcode,options) |
| 56 %><sub><% to_html(bbcode.contents,options) %></sub><% | |
| 57 end | |
| 58 | |
| 20 | 59 function html.brackets(bbcode,options) |
| 60 %>[<% to_html(bbcode.contents,options) %>]<% | |
| 61 end | |
| 62 | |
| 63 function html.url(bbcode,options) | |
| 12 | 64 local url = bbcode.param |
| 65 if url == nil then | |
| 66 url = html_encode(bbcode.contents) | |
| 67 %><a href="<%=url%>"><%=url%></a><% | |
| 68 else | |
| 69 url = html_encode(url) | |
| 20 | 70 %><a href="<%=url%>"><% to_html(bbcode.contents,options) %></a><% |
| 12 | 71 end |
| 72 end | |
| 73 | |
| 20 | 74 function html.code(bbcode,options) |
| 49 | 75 if bbcode.param == "inline" then |
| 76 %><code inline><%= html_encode(bbcode.contents) %></code><% | |
| 77 else | |
| 78 local s = starting_cr_regex.gsub(bbcode.contents,"") | |
| 79 %><code><%= html_encode(s) %></code><% | |
| 80 options.strip_newline = true | |
| 81 end | |
| 12 | 82 end |
| 83 | |
| 20 | 84 function html.img(bbcode,options) |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
85 %><img src="<%= html_encode(bbcode.contents) %>"<% |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
86 if bbcode.param ~= nil then |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
87 %> width="<%=bbcode.param%>"<% |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
88 end |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
89 %>><% |
| 12 | 90 end |
| 91 | |
| 20 | 92 function html.color(bbcode,options) |
| 93 %><span style="color:<%=bbcode.param%>"><% to_html(bbcode.contents,options) %></span><% | |
| 12 | 94 end |
| 95 | |
| 20 | 96 function html.size(bbcode,options) |
| 23 | 97 %><span style="font-size:<%=bbcode.param%>"><% to_html(bbcode.contents,options) %></span><% |
| 12 | 98 end |
| 99 | |
| 20 | 100 function html.quote(bbcode,options) |
| 12 | 101 %><blockquote><% |
| 102 local user_name = bbcode.param | |
| 103 if user_name ~= nil then | |
| 104 local user = User.get_by_name(user_name) | |
| 105 if user == nil then | |
| 106 %><%= user_name %> wrote:<% | |
| 107 else | |
| 108 %><a href="/user_something"><%= user_name %></a> wrote:<% | |
| 109 end | |
| 20 | 110 else |
| 111 options.strip_newline = true | |
| 12 | 112 end |
| 20 | 113 to_html(bbcode.contents,options) |
| 12 | 114 %></blockquote><% |
| 20 | 115 options.strip_newline = true |
| 12 | 116 end |
| 117 | |
| 28 | 118 local function video_iframe(url) |
| 119 %><iframe width="560" height="315" frameborder="0" allowfullscreen src="<%=url%>"></iframe><% | |
| 120 end | |
| 121 | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
122 local video_urls = { |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
123 [[\.mp4$]] |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
124 } |
| 28 | 125 local video_handlers = {} |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
126 local function regex_video(s) |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
127 video_urls[#video_urls+1] = s |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
128 return regex(s) |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
129 end |
| 28 | 130 do |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
131 local ptn1 = regex_video[[^\Qhttps://youtu.be/\E([a-zA-Z0-9_-]+)(?:\?t=([0-9]+))?]] |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
132 local ptn2 = regex_video[[^\Qhttps://www.youtube.com/watch?v=\E([a-zA-Z0-9_-]+)(?:&t=([0-9]+)s)?]] |
| 28 | 133 function video_handlers.youtube(url) |
| 29 | 134 local id, start = ptn1.match(url) |
| 28 | 135 if id == nil then |
| 29 | 136 id, start = ptn2.match(url) |
| 28 | 137 end |
| 138 if id == nil then | |
| 139 return false | |
| 140 end | |
| 141 url = "https://www.youtube.com/embed/"..id | |
| 142 if start ~= nil then | |
| 143 url = url.."?start="..start | |
| 144 end | |
| 145 video_iframe(url) | |
| 146 return true | |
| 147 end | |
| 148 end | |
| 149 do | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
150 local ptn = regex_video[[^\Qhttps://rumble.com/embed/\E[a-z0-9]+/\?pub=[a-z0-9]+]] |
| 28 | 151 function video_handlers.rumble(url) |
| 29 | 152 if not ptn.matches(url) then |
| 28 | 153 return false |
| 154 end | |
| 155 video_iframe(url) | |
| 156 return true | |
| 157 end | |
| 158 end | |
| 159 do | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
160 local ptn = regex_video[[^\Qhttps://www.bitchute.com/video/\E([a-zA-Z0-9]+)/]] |
| 28 | 161 function video_handlers.bitchute(url) |
| 29 | 162 local id = ptn.match(url) |
| 28 | 163 if id == nil then |
| 164 return false | |
| 165 end | |
| 166 url = "https://www.bitchute.com/embed/"..id.."/" | |
| 167 video_iframe(url) | |
| 168 return true | |
| 169 end | |
| 170 end | |
| 171 do | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
172 local ptn = regex_video[[^\Qhttps://vimeo.com/\E([0-9]+)]] |
| 28 | 173 function video_handlers.vimeo(url) |
| 29 | 174 local id = ptn.match(url) |
| 28 | 175 if id == nil then |
| 176 return false | |
| 177 end | |
| 178 url = "https://player.vimeo.com/video/"..id | |
| 179 video_iframe(url) | |
| 180 return true | |
| 181 end | |
| 182 end | |
| 183 do | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
184 local ptn = regex_video[[^\Qhttps://dai.ly/\E([a-z0-9]+)]] |
| 28 | 185 function video_handlers.dailymotion(url) |
| 29 | 186 local id = ptn.match(url) |
| 28 | 187 if id == nil then |
| 188 return false | |
| 189 end | |
| 190 url = "https://www.dailymotion.com/embed/video/"..id | |
| 191 video_iframe(url) | |
| 192 return true | |
| 193 end | |
| 194 end | |
| 195 do | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
196 local ptn = regex_video[[^\Qhttps://www.tiktok.com/\E[^/]+/video/([0-9]+)]] |
| 28 | 197 function video_handlers.tiktok(url) |
| 29 | 198 local id = ptn.match(url) |
| 28 | 199 if id == nil then |
| 200 return false | |
| 201 end | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
202 %><iframe allowfullscreen scrolling="no" width="325" height="720" src="https://www.tiktok.com/embed/<%=id%>"></iframe><% |
| 28 | 203 return true |
| 204 end | |
| 205 end | |
| 206 do | |
| 29 | 207 local ptn = regex[[\.[a-zA-Z0-9]+$]] |
| 28 | 208 function video_handlers.file(url) |
| 29 | 209 if not ptn.matches(url) then |
| 28 | 210 return false |
| 211 end | |
| 212 %><video controls width="560"><source src="<%=html_encode(url)%>"></video><% | |
| 213 return true | |
| 214 end | |
| 215 end | |
| 23 | 216 |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
217 local video_regex = regex(concat(video_urls,"|")) |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
218 |
| 20 | 219 function html.video(bbcode,options) |
| 23 | 220 local url = bbcode.contents |
| 28 | 221 for _, handle in pairs(video_handlers) do |
| 222 if handle(url) then return end | |
| 27 | 223 end |
| 23 | 224 url = html_encode(url) |
| 225 %><a href="<%=url%>"><%=url%></a><% | |
| 12 | 226 end |
| 227 | |
| 20 | 228 local function list_to_html(bbcode,options) |
| 229 local list = to_list(bbcode.contents) | |
| 230 for _, item in ipairs(list) do | |
| 48 | 231 if type(item) == "table" and item.name == "item" then |
| 20 | 232 %><li><% to_html(item.contents,options) %></li><% |
| 233 end | |
| 234 end | |
| 235 options.strip_newline = true | |
| 236 end | |
| 237 | |
| 48 | 238 function html.list(bbcode,options) |
| 239 local tag = bbcode.param == "1" and "ol" or "ul" | |
| 240 %><<%=tag%>><% | |
| 20 | 241 list_to_html(bbcode,options) |
| 48 | 242 %></<%=tag%>><% |
| 20 | 243 end |
| 244 | |
| 245 function to_html(bbcode,options) | |
| 246 if options.strip_newline then | |
| 247 if type(bbcode) == "string" then | |
| 29 | 248 bbcode = starting_cr_regex.gsub(bbcode,"") |
| 20 | 249 end |
| 250 options.strip_newline = false | |
| 251 end | |
| 12 | 252 if type(bbcode) == "string" then |
| 253 %><%= html_encode(bbcode) %><% | |
| 254 else | |
| 255 type(bbcode) == "table" or error() | |
| 256 if is_list(bbcode) then | |
| 257 for _, v in ipairs(bbcode) do | |
| 20 | 258 to_html(v,options) |
| 12 | 259 end |
| 260 else | |
| 261 local fn = html[bbcode.name] or error(bbcode.name.." not handled") | |
| 20 | 262 fn(bbcode,options) |
| 12 | 263 end |
| 264 end | |
| 265 end | |
| 266 | |
| 267 function Bbcode.to_html(bbcode) | |
| 268 bbcode = bbcode_parse(bbcode) | |
| 49 | 269 %><div from_bbcode><% |
| 20 | 270 to_html(bbcode,{strip_newline=false}) |
| 271 %></div><% | |
| 12 | 272 end |
| 273 | |
| 13 | 274 |
| 275 local doesnt_nest = list_to_set{ | |
| 276 "url" | |
| 277 "code" | |
| 278 "img" | |
| 279 "video" | |
| 280 } | |
| 281 | |
| 29 | 282 local url_regex = regex[[(^|\s)(https?://\S+)]] |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
283 local img_regex |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
284 do |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
285 local endings = { |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
286 "jpg" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
287 "jpeg" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
288 "png" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
289 "gif" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
290 "svg" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
291 } |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
292 local t = {} |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
293 for _, ending in ipairs(endings) do |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
294 t[#t+1] = [[\.]]..ending..[[$]] |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
295 end |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
296 img_regex = regex(concat(t,"|")) |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
297 end |
| 29 | 298 |
| 13 | 299 local function preprocess(bbcode) |
| 300 if type(bbcode) == "string" then | |
|
53
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
301 bbcode = url_regex.gsub( bbcode, function(prefix,url) |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
302 if video_regex.matches(url) then |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
303 return prefix.."[video]"..url.."[/video]" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
304 elseif img_regex.matches(url) then |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
305 return prefix.."[img]"..url.."[/img]" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
306 else |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
307 return prefix.."[url]"..url.."[/url]" |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
308 end |
|
cac477dd1f82
convert image and video urls
Franklin Schmidt <fschmidt@gmail.com>
parents:
49
diff
changeset
|
309 end ) |
| 13 | 310 %><%= bbcode %><% |
| 311 else | |
| 312 type(bbcode) == "table" or error() | |
| 313 if is_list(bbcode) then | |
| 314 for _, v in ipairs(bbcode) do | |
| 315 preprocess(v) | |
| 316 end | |
| 317 else | |
| 318 local name = bbcode.name | |
| 319 local param = bbcode.param | |
| 320 %>[<%=name%><% | |
| 321 if param ~= nil then | |
| 322 %>=<%=param%><% | |
| 323 end | |
| 324 %>]<% | |
| 325 if doesnt_nest[name] then | |
| 326 %><%=bbcode.contents%><% | |
| 327 else | |
| 328 preprocess(bbcode.contents) | |
| 329 end | |
| 20 | 330 if name == "code" and param ~= nil then |
| 331 %>[/<%=name%>=<%=param%>]<% | |
| 332 else | |
| 333 %>[/<%=name%>]<% | |
| 334 end | |
| 13 | 335 end |
| 336 end | |
| 337 end | |
| 338 | |
| 43 | 339 -- url handling |
| 13 | 340 function Bbcode.preprocess(bbcode) |
| 341 bbcode = bbcode_parse(bbcode) | |
| 342 return output_of(function() | |
| 343 preprocess(bbcode) | |
| 344 end) | |
| 345 end | |
| 346 | |
| 21 | 347 function Bbcode.remove_html(text) |
| 29 | 348 local ends_with_newline = ends_with(text,"\n") |
| 21 | 349 local t = {} |
| 350 local html = html_parse(text) | |
| 351 local is_first = true | |
| 352 for _, v in ipairs(html) do | |
| 353 if type(v) == "string" then | |
| 354 t[#t+1] = v | |
| 355 else | |
| 356 local name = v.name | |
| 357 if name == "div" then | |
| 358 if not is_first then | |
| 359 t[#t+1] = "\n" | |
| 360 end | |
| 361 elseif name == "/div" or name == "br" then | |
| 362 -- ignore | |
| 363 else | |
| 364 error("unexpected tag: "..name) | |
| 365 end | |
| 366 end | |
| 367 is_first = false | |
| 368 end | |
| 369 if not ends_with_newline then | |
| 370 t[#t+1] = "\n" | |
| 371 end | |
| 372 return concat(t) | |
| 373 end | |
| 374 | |
| 375 | |
| 12 | 376 return Bbcode |
