Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/banzai/filter/truncate_visible_filter.rb69
-rw-r--r--lib/banzai/pipeline/post_process_pipeline.rb1
2 files changed, 70 insertions, 0 deletions
diff --git a/lib/banzai/filter/truncate_visible_filter.rb b/lib/banzai/filter/truncate_visible_filter.rb
new file mode 100644
index 00000000000..edd6efd4706
--- /dev/null
+++ b/lib/banzai/filter/truncate_visible_filter.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+module Banzai
+ module Filter
+ class TruncateVisibleFilter < HTML::Pipeline::Filter
+ # Truncates the document to `truncate_visible_max_chars` characters,
+ # excluding any HTML tags.
+
+ MATCH_CODE = 'pre > code > .line'
+
+ def call
+ return doc unless context[:truncate_visible_max_chars].present?
+
+ max_chars = context[:truncate_visible_max_chars]
+ content_length = 0
+ @truncated = false
+
+ doc.traverse do |node|
+ if node.text? || node.content.empty?
+ if truncated
+ node.remove
+ next
+ end
+
+ handle_line_breaks(node)
+ truncate_content(content_length, max_chars, node)
+
+ content_length += node.content.length
+ end
+
+ truncate_if_block(node)
+ end
+
+ doc
+ end
+
+ private
+
+ attr_reader :truncated
+
+ def truncate_content(content_length, max_chars, node)
+ num_remaining = max_chars - content_length
+ return unless node.content.length > num_remaining
+
+ node.content = node.content.truncate(num_remaining)
+ @truncated = true
+ end
+
+ # Handle line breaks within a node
+ def handle_line_breaks(node)
+ return unless node.content.strip.lines.length > 1
+
+ node.content = "#{node.content.lines.first.chomp}..."
+ @truncated = true
+ end
+
+ # If `node` is the first block element, and the
+ # text hasn't already been truncated, then append "..." to the node contents
+ # and return true. Otherwise return false.
+ def truncate_if_block(node)
+ return if truncated
+ return unless node.element? && (node.description&.block? || node.matches?(MATCH_CODE))
+
+ node.inner_html = "#{node.inner_html}..." if node.next_sibling
+ @truncated = true
+ end
+ end
+ end
+end
diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb
index da2262cdf83..f8035698b9b 100644
--- a/lib/banzai/pipeline/post_process_pipeline.rb
+++ b/lib/banzai/pipeline/post_process_pipeline.rb
@@ -5,6 +5,7 @@ module Banzai
class PostProcessPipeline < BasePipeline
def self.filters
@filters ||= FilterArray[
+ Filter::TruncateVisibleFilter,
*internal_link_filters,
Filter::AbsoluteLinkFilter,
Filter::BroadcastMessagePlaceholdersFilter