require 'nokogiri' module GitlabMarkdownHelper # Use this in places where you would normally use link_to(gfm(...), ...). # # It solves a problem occurring with nested links (i.e. # "outer text gfm ref more outer text"). This will not be # interpreted as intended. Browsers will parse something like # "outer text gfm ref more outer text" (notice the last part is # not linked any more). link_to_gfm corrects that. It wraps all parts to # explicitly produce the correct linking behavior (i.e. # "outer text gfm ref more outer text"). def link_to_gfm(body, url, html_options = {}) return "" if body.blank? escaped_body = if body =~ /\A\ at the beginning of a line", "Make a horizontal line using three or more hyphens ---, asterisks ***, or underscores ___" ].freeze # Returns a random markdown tip for use as a textarea placeholder def random_markdown_tip MARKDOWN_TIPS.sample end private # Return +text+, truncated to +max_chars+ characters, excluding any HTML # tags. def truncate_visible(text, max_chars) doc = Nokogiri::HTML.fragment(text) content_length = 0 truncated = false doc.traverse do |node| if node.text? || node.content.empty? if truncated node.remove next end # Handle line breaks within a node if node.content.strip.lines.length > 1 node.content = "#{node.content.lines.first.chomp}..." truncated = true end num_remaining = max_chars - content_length if node.content.length > num_remaining node.content = node.content.truncate(num_remaining) truncated = true end content_length += node.content.length end truncated = truncate_if_block(node, truncated) end doc.to_html end # Used by #truncate_visible. 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, truncated) if node.element? && node.description.block? && !truncated node.inner_html = "#{node.inner_html}..." if node.next_sibling true else truncated end end # Returns the text necessary to reference `entity` across projects # # project - Project to reference # entity - Object that responds to `to_reference` # # Examples: # # cross_project_reference(project, project.issues.first) # # => 'namespace1/project1#123' # # cross_project_reference(project, project.merge_requests.first) # # => 'namespace1/project1!345' # # Returns a String def cross_project_reference(project, entity) if entity.respond_to?(:to_reference) "#{project.to_reference}#{entity.to_reference}" else '' end end end