summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--lib/banzai/filter/autolink_filter.rb15
2 files changed, 10 insertions, 6 deletions
diff --git a/CHANGELOG b/CHANGELOG
index c099c63ce86..47e959dea68 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,7 @@ v 8.11.0 (unreleased)
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
- Optimize maximum user access level lookup in loading of notes
- Add "No one can push" as an option for protected branches. !5081
+ - Improve performance of AutolinkFilter#text_parse by using XPath
- Environments have an url to link to
- Limit git rev-list output count to one in forced push check
- Clean up unused routes (Josef Strzibny)
diff --git a/lib/banzai/filter/autolink_filter.rb b/lib/banzai/filter/autolink_filter.rb
index 9ed45707515..799b83b1069 100644
--- a/lib/banzai/filter/autolink_filter.rb
+++ b/lib/banzai/filter/autolink_filter.rb
@@ -31,6 +31,14 @@ module Banzai
# Text matching LINK_PATTERN inside these elements will not be linked
IGNORE_PARENTS = %w(a code kbd pre script style).to_set
+ # The XPath query to use for finding text nodes to parse.
+ TEXT_QUERY = %Q(descendant-or-self::text()[
+ not(#{IGNORE_PARENTS.map { |p| "ancestor::#{p}" }.join(' or ')})
+ and contains(., '://')
+ and not(starts-with(., 'http'))
+ and not(starts-with(., 'ftp'))
+ ])
+
def call
return doc if context[:autolink] == false
@@ -66,16 +74,11 @@ module Banzai
# Autolinks any text matching LINK_PATTERN that Rinku didn't already
# replace
def text_parse
- search_text_nodes(doc).each do |node|
+ doc.xpath(TEXT_QUERY).each do |node|
content = node.to_html
- next if has_ancestor?(node, IGNORE_PARENTS)
next unless content.match(LINK_PATTERN)
- # If Rinku didn't link this, there's probably a good reason, so we'll
- # skip it too
- next if content.start_with?(*%w(http https ftp))
-
html = autolink_filter(content)
next if html == content