2
0
mirror of https://github.com/moebooru/moebooru synced 2025-08-22 09:57:31 +00:00
moebooru/lib/dtext.rb

131 lines
4.4 KiB
Ruby
Raw Normal View History

# encoding: utf-8
module DText
def parse(str)
2014-12-05 23:54:08 +09:00
return "" unless str
2024-01-08 19:39:01 +09:00
state = [ "newline" ]
2012-05-13 08:22:42 +07:00
result = ""
2012-05-22 06:58:09 +07:00
# Normalize newlines.
str.strip!
str.gsub!(/(\r\n?)/, "\n")
2012-05-13 08:22:42 +07:00
str.gsub!(/\n{3,}/, "\n\n")
2012-05-18 21:28:38 +07:00
str = CGI.escapeHTML str
2012-11-18 19:07:02 +07:00
# Nuke spaces between newlines.
str.gsub!(/ *\n */, "\n")
2012-05-22 06:58:09 +07:00
# Keep newline, use carriage return for split.
str.gsub!("\n", "\n\r")
2012-05-10 12:35:11 +07:00
data = str.split("\r")
2012-05-22 06:58:09 +07:00
# Parse header and list first, line by line.
data.each do |d|
2012-05-13 08:22:42 +07:00
result << parseline(d, state)
end
2012-05-22 06:58:09 +07:00
# Parse inline tags as a whole.
result = parseinline(result)
2012-05-22 06:58:09 +07:00
# Nokogiri ensures valid html output.
2012-05-13 08:22:42 +07:00
Nokogiri::HTML::DocumentFragment.parse(result).to_html
end
def parseinline(str)
2012-05-22 06:58:09 +07:00
# Short links subtitution:
2012-05-25 10:18:21 -07:00
str.gsub!(/\[\[(.+?)\]\]/) do # [[title]] or [[title|label]] ;link to wiki
data = Regexp.last_match[1].split("|", 2)
2012-05-25 10:18:21 -07:00
title = data[0]
label = data[1].nil? ? title : data[1]
"<a href=\"/wiki/show?title=#{CGI.escape(CGI.unescapeHTML(title.tr(" ", "_")))}\">#{label}</a>"
end
2012-05-19 00:44:11 +07:00
str.gsub!(/\{\{(.+?)\}\}/) do # {{post tags here}} ;search post with tags
"<a href=\"/post?tags=#{CGI.escape(CGI.unescapeHTML(Regexp.last_match[1]))}\">#{Regexp.last_match[1]}</a>"
end
2012-05-22 06:58:09 +07:00
# Miscellaneous single line tags subtitution.
str.gsub! /\[b\](.+?)\[\/b\]/, '<strong>\1</strong>'
str.gsub! /\[i\](.+?)\[\/i\]/, '<em>\1</em>'
str.gsub! /(post #(\d+))/i, '<a href="/post/show/\2">\1</a>'
str.gsub! /(forum #(\d+))/i, '<a href="/forum/show/\2">\1</a>'
str.gsub! /(comment #(\d+))/i, '<a href="/comment/show/\2">\1</a>'
str.gsub! /(pool #(\d+))/i, '<a href="/pool/show/\2">\1</a>'
2012-05-22 06:58:09 +07:00
# Single line spoiler tags.
2020-04-22 05:15:23 +09:00
str.gsub! /\[spoilers?\](.+?)\[\/spoilers?\]/, '<span class="spoiler js-comment--spoiler"><span class="spoilerwarning">spoiler</span></span><span class="spoilertext" style="display: none">\1</span>'
str.gsub! /\[spoilers?=(.+?)\](.+?)\[\/spoilers?\]/, '<span class="spoiler js-comment--spoiler"><span class="spoilerwarning">\1</span></span><span class="spoilertext" style="display: none">\2</span>'
2012-05-22 06:58:09 +07:00
# Multi line spoiler tags.
2020-04-22 05:15:23 +09:00
str.gsub! /\[spoilers?\]/, '<span class="spoiler js-comment--spoiler"><span class="spoilerwarning">spoiler</span></span><div class="spoilertext" style="display: none">'
str.gsub! /\[spoilers?=(.+?)\]/, '<span class="spoiler js-comment--spoiler"><span class="spoilerwarning">\1</span></span><div class="spoilertext" style="display: none">'
str.gsub! /\[\/spoilers?\]/, "</div>"
2012-05-22 06:58:09 +07:00
# Quote.
str.gsub! /\[quote\]/, "<blockquote><div>"
str.gsub! /\[\/quote\]/, "</div></blockquote>"
2012-05-16 05:38:28 +07:00
str = parseurl(str)
# Extraneous newlines before closing div are unnecessary.
str.gsub! /\n+(<\/div>)/, '\1'
2012-05-28 20:00:53 -07:00
# So are after headers, lists, and blockquotes.
str.gsub! /(<\/(ul|h\d+|blockquote)>)\n+/, '\1'
2012-07-01 10:11:17 -07:00
# And after opening blockquote.
str.gsub! /(<blockquote><div>)\n+/, '\1'
str.gsub! /\n/, "<br>"
2012-05-13 09:30:00 +07:00
str
end
2012-05-13 08:22:42 +07:00
def parseline(str, state)
if state.last =~ /\d/ || str =~ /^\*+\s+/
2012-05-13 08:22:42 +07:00
parselist str, state
elsif str =~ /^(h[1-6])\.\s*(.+)\n*/
"<#{Regexp.last_match[1]}>#{Regexp.last_match[2]}</#{Regexp.last_match[1]}>"
2012-05-13 08:22:42 +07:00
else
2012-05-18 22:38:31 +07:00
str
2012-05-13 08:22:42 +07:00
end
end
2012-05-13 08:22:42 +07:00
def parselist(str, state)
html = ""
if state.last =~ /\d/
n = ((str =~ /^\*+\s+/ && str.split[0]) || "").count("*")
2012-05-13 08:22:42 +07:00
if n < state.last.to_i
html << "</ul>" * (state.last.to_i - n)
2012-05-13 08:22:42 +07:00
state[-1] = n.to_s
elsif n > state.last.to_i
html << "<ul>"
2012-05-13 08:22:42 +07:00
state[-1] = (state.last.to_i + 1).to_s
end
unless str =~ /^\*+\s+/
state.pop
return html + parseline(str, state)
end
else
state.push "1"
html << "<ul>"
2012-05-13 08:22:42 +07:00
end
html << str.gsub(/\*+\s+(.+)\n*/, '<li>\1')
2012-05-13 08:22:42 +07:00
end
2012-05-13 08:22:42 +07:00
def parseurl(str)
2014-03-09 23:06:06 +09:00
# url
str.gsub! %r{(^|[\s\(>])(h?ttps?://(?:(?!&gt;&gt;)[^\s<"])+[^\s<".])}, '\1<a href="\2">\2</a>'
# <<url|label>>
str.gsub! %r{&lt;&lt;(h?ttps?://(?:(?!&gt;&gt;).)+)\|((?:(?!&gt;&gt;).)+)&gt;&gt;}, '<a href="\1">\2</a>'
# <<url>>
str.gsub! %r{&lt;&lt;(h?ttps?:\/\/(?:(?!&gt;&gt;).)+)&gt;&gt;}, '<a href="\1">\1</a>'
# "label":url
str.gsub! %r{(^|[\s>])&quot;((?:(?!&quot;).)+)&quot;:(h?ttps?://[^\s<"]+[^\s<".])}, '\1<a href="\3">\2</a>'
# Fix ttp(s) scheme
str.gsub! /<a href="ttp/, '<a href="http'
str
end
2012-05-16 01:26:30 +07:00
module_function :parse, :parseline, :parseinline, :parselist, :parseurl
end