diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/banzai/filter/truncate_visible_filter.rb | 69 | ||||
-rw-r--r-- | lib/banzai/pipeline/post_process_pipeline.rb | 1 |
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 |