more domain handling, inline link rewriting
This commit is contained in:
BIN
app/assets/images/domain-icons/redbubble.png
Normal file
BIN
app/assets/images/domain-icons/redbubble.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
BIN
app/assets/images/domain-icons/spreadshirt.png
Normal file
BIN
app/assets/images/domain-icons/spreadshirt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
app/assets/images/domain-icons/telegram.png
Normal file
BIN
app/assets/images/domain-icons/telegram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
app/assets/images/domain-icons/weasyl.png
Normal file
BIN
app/assets/images/domain-icons/weasyl.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -5,6 +5,7 @@ module Domain::DescriptionsHelper
|
||||
extend T::Helpers
|
||||
include HelpersInterface
|
||||
include Domain::PostsHelper
|
||||
include Domain::DomainsHelper
|
||||
requires_ancestor { Object }
|
||||
|
||||
abstract!
|
||||
@@ -33,6 +34,13 @@ module Domain::DescriptionsHelper
|
||||
nil
|
||||
end
|
||||
|
||||
sig { params(text: String, url: String).returns(T::Boolean) }
|
||||
def text_same_as_url?(text, url)
|
||||
text = text.strip
|
||||
url = url.strip
|
||||
["", "http://", "https://"].any? { |prefix| "#{prefix}#{text}" == url }
|
||||
end
|
||||
|
||||
sig { params(model: HasDescriptionHtmlForView).returns(T.nilable(String)) }
|
||||
def sanitize_description_html(model)
|
||||
html = model.description_html_for_view
|
||||
@@ -87,7 +95,32 @@ module Domain::DescriptionsHelper
|
||||
next { node_whitelist: [] } if url.nil?
|
||||
|
||||
found_link = link_for_source(url.to_s)
|
||||
next { node_whitelist: [] } if found_link.nil?
|
||||
if found_link.nil?
|
||||
if ALLOWED_EXTERNAL_LINK_DOMAINS.any? { |domain|
|
||||
url_matches_domain?(domain, url.host)
|
||||
}
|
||||
if text_same_as_url?(node.text, url.to_s)
|
||||
title = title_for_url(url.to_s)
|
||||
else
|
||||
title = node.text
|
||||
end
|
||||
|
||||
replacements[node] = Nokogiri::HTML5.fragment(
|
||||
render(
|
||||
partial:
|
||||
"domain/has_description_html/inline_link_external",
|
||||
locals: {
|
||||
url: url.to_s,
|
||||
text: title,
|
||||
icon_path: icon_path_for_domain(url.host),
|
||||
},
|
||||
),
|
||||
)
|
||||
next { node_whitelist: [node] }
|
||||
else
|
||||
next { node_whitelist: [] }
|
||||
end
|
||||
end
|
||||
|
||||
found_model = found_link.model
|
||||
partial, as =
|
||||
|
||||
99
app/helpers/domain/domains_helper.rb
Normal file
99
app/helpers/domain/domains_helper.rb
Normal file
@@ -0,0 +1,99 @@
|
||||
# typed: strict
|
||||
module Domain::DomainsHelper
|
||||
extend T::Sig
|
||||
extend T::Helpers
|
||||
include HelpersInterface
|
||||
abstract!
|
||||
|
||||
ALLOWED_EXTERNAL_LINK_DOMAINS = %w[
|
||||
youtube.com
|
||||
x.com
|
||||
weasyl.com
|
||||
vimeo.com
|
||||
twitter.com
|
||||
twitch.tv
|
||||
tumblr.com
|
||||
t.me
|
||||
spreadshirt.de
|
||||
spreadshirt.com
|
||||
redbubble.com
|
||||
pixiv.net
|
||||
pinterest.com
|
||||
patreon.com
|
||||
mstdn.social
|
||||
livejournal.com
|
||||
ko-fi.com
|
||||
instagram.com
|
||||
facebook.com
|
||||
dribbble.com
|
||||
discord.gg
|
||||
deviantart.com
|
||||
bsky.app
|
||||
behance.net
|
||||
gumroad.com
|
||||
bigcartel.com
|
||||
].freeze
|
||||
|
||||
DOMAIN_TO_ICON_PATH =
|
||||
T.let(
|
||||
{
|
||||
"x.com" => "x-twitter.png",
|
||||
"wixmp.com" => "deviantart.png",
|
||||
"weasyl.com" => "weasyl.png",
|
||||
"twitter.com" => "x-twitter.png",
|
||||
"t.me" => "telegram.png",
|
||||
"pixiv.net" => "pixiv.png",
|
||||
"patreon.com" => "patreon.png",
|
||||
"newgrounds.com" => "newgrounds.png",
|
||||
"itaku.ee" => "itaku.png",
|
||||
"inkbunny.net" => "inkbunny.png",
|
||||
"ib.metapix.net" => "inkbunny.png",
|
||||
"furaffinity.net" => "fa.png",
|
||||
"e621.net" => "e621.png",
|
||||
"deviantart.com" => "deviantart.png",
|
||||
"bsky.app" => "bsky.png",
|
||||
"redbubble.com" => "redbubble.png",
|
||||
"spreadshirt.de" => "spreadshirt.png",
|
||||
"spreadshirt.com" => "spreadshirt.png",
|
||||
}.freeze,
|
||||
T::Hash[String, String],
|
||||
)
|
||||
|
||||
DOMAIN_TITLE_MAPPERS =
|
||||
T.let(
|
||||
[
|
||||
[%r{://t.me/([^/]+)}, ->(match) { match[1] }],
|
||||
[%r{://bsky.app/profile/([^/]+)}, ->(match) { match[1] }],
|
||||
[%r{://(.*\.)?x.com/([^/]+)}, ->(match) { match[2] }],
|
||||
[%r{://(.*\.)?twitter.com/([^/]+)}, ->(match) { match[2] }],
|
||||
[%r{://(.*\.)?patreon.com/([^/]+)}, ->(match) { match[2] }],
|
||||
],
|
||||
T::Array[[Regexp, T.proc.params(match: MatchData).returns(String)]],
|
||||
)
|
||||
|
||||
sig { params(domain: String, host: String).returns(T::Boolean) }
|
||||
def url_matches_domain?(domain, host)
|
||||
host == domain || host.end_with?(".#{domain}")
|
||||
end
|
||||
|
||||
sig { params(domain: String).returns(T.nilable(String)) }
|
||||
def icon_path_for_domain(domain)
|
||||
for test_domain, icon in DOMAIN_TO_ICON_PATH
|
||||
if url_matches_domain?(test_domain, domain)
|
||||
return asset_path("domain-icons/#{icon}")
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
sig { params(url: String).returns(String) }
|
||||
def title_for_url(url)
|
||||
url = url.to_s
|
||||
for mapper in DOMAIN_TITLE_MAPPERS
|
||||
if (match = mapper[0].match(url)) && (group = mapper[1].call(match))
|
||||
return group
|
||||
end
|
||||
end
|
||||
url
|
||||
end
|
||||
end
|
||||
@@ -6,6 +6,7 @@ module Domain::PostsHelper
|
||||
include LogEntriesHelper
|
||||
include Domain::UsersHelper
|
||||
include PathsHelper
|
||||
include Domain::DomainsHelper
|
||||
abstract!
|
||||
|
||||
class DomainData < T::Struct
|
||||
@@ -121,29 +122,7 @@ module Domain::PostsHelper
|
||||
def icon_asset_for_url(url)
|
||||
domain = extract_domain(url)
|
||||
return nil unless domain
|
||||
|
||||
domain_patterns = {
|
||||
%w[*.e621.net e621.net] => "e621.png",
|
||||
%w[*.furaffinity.net furaffinity.net] => "fa.png",
|
||||
%w[*.bsky.app bsky.app] => "bsky.png",
|
||||
%w[*.itaku.ee itaku.ee] => "itaku.png",
|
||||
%w[*.deviantart.com deviantart.com *.wixmp.com] => "deviantart.png",
|
||||
%w[*.twitter.com twitter.com *.x.com x.com] => "x-twitter.png",
|
||||
%w[*.inkbunny.net inkbunny.net *.ib.metapix.net ib.metapix.net] =>
|
||||
"inkbunny.png",
|
||||
%w[*.newgrounds.com newgrounds.com] => "newgrounds.png",
|
||||
%w[*.patreon.com patreon.com] => "patreon.png",
|
||||
%w[*.pixiv.net pixiv.net *.pximg.net pximg.net] => "pixiv.png",
|
||||
}
|
||||
|
||||
domain_patterns.each do |patterns, icon|
|
||||
patterns.each do |pattern|
|
||||
if File.fnmatch?(pattern, domain, File::FNM_PATHNAME)
|
||||
return asset_path("domain-icons/#{icon}")
|
||||
end
|
||||
end
|
||||
end
|
||||
nil
|
||||
icon_path_for_domain(domain)
|
||||
end
|
||||
|
||||
sig { params(category: Symbol).returns(String) }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<%= link_to(
|
||||
url,
|
||||
target: "_blank noopener noreferrer nofollow",
|
||||
class:
|
||||
"hover:underline text-slate-200 bg-slate-800 hover:text-slate-100 hover:bg-slate-700 border-slate-500 border rounded-md px-1 whitespace-nowrap inline-flex items-center gap-1 align-top",
|
||||
) do %>
|
||||
<% if local_assigns[:icon_path] %>
|
||||
<%= image_tag local_assigns[:icon_path], class: "w-4 h-4 inline-block rounded-sm" %>
|
||||
<% end %>
|
||||
<span><%= text %></span>
|
||||
<% end %>
|
||||
Reference in New Issue
Block a user