Module: MarkupHelper

Instance Method Summary collapse

Instance Method Details

#cross_project_reference(project, entity) ⇒ Object

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



148
149
150
151
152
153
154
# File 'app/helpers/markup_helper.rb', line 148

def cross_project_reference(project, entity)
  if entity.respond_to?(:to_reference)
    entity.to_reference(project, full: true)
  else
    ''
  end
end

#first_line_in_markdown(object, attribute, max_chars = nil, **options) ⇒ Object

Return the first line of text, up to max_chars, after parsing the line as Markdown. HTML tags in the parsed output are not counted toward the max_chars limit. If the length limit falls within a tag’s contents, then the tag contents are truncated without removing the closing tag.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'app/helpers/markup_helper.rb', line 62

def first_line_in_markdown(object, attribute, max_chars = nil, **options)
  md = markdown_field(object, attribute, options.merge(post_process: false))
  return unless md.present?

  tags = %w[a gl-emoji b strong i em pre code p span]

  context = markdown_field_render_context(object, attribute, options)
  context.reverse_merge!(truncate_visible_max_chars: max_chars || md.length)

  text = prepare_for_rendering(md, context)
  text = sanitize(
    text,
    tags: tags,
    attributes: Rails::Html::WhiteListSanitizer.allowed_attributes +
      %w[
        style data-src data-name data-unicode-version data-html data-fallback-src
        data-reference-type data-project-path data-iid data-mr-title
        data-user
      ]
  )

  render_links(text)
end

It solves a problem occurring with nested links (i.e. “<a>outer text <a>gfm ref</a> more outer text</a>”). This will not be interpreted as intended. Browsers will parse something like “<a>outer text </a><a>gfm ref</a> more outer text” (notice the last part is not linked any more). link_to_html corrects that. It wraps all parts to explicitly produce the correct linking behavior (i.e. “<a>outer text </a><a>gfm ref</a><a> more outer text</a>”).



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'app/helpers/markup_helper.rb', line 29

def link_to_html(redacted, url, html_options = {})
  fragment = Nokogiri::HTML::DocumentFragment.parse(redacted)

  if fragment.children.size == 1 && fragment.children[0].name == 'a'
    # Fragment has only one node, and it's a link generated by `gfm`.
    # Replace it with our requested link.
    text = fragment.children[0].text
    fragment.children[0].replace(link_to(text, url, html_options))
  else
    # Traverse the fragment's first generation of children looking for
    # either pure text or emojis, wrapping anything found in the
    # requested link
    fragment.children.each do |node|
      if node.text?
        node.replace(link_to(node.text, url, html_options))
      elsif node.name == 'gl-emoji'
        node.replace(link_to(node.to_html.html_safe, url, html_options))
      end
    end
  end

  # Add any custom CSS classes to the GFM-generated reference links
  if html_options[:class]
    fragment.css('a.gfm').add_class(html_options[:class])
  end

  fragment.to_html.html_safe
end

Use this in places where you would normally use link_to(gfm(…), …).



10
11
12
13
14
# File 'app/helpers/markup_helper.rb', line 10

def link_to_markdown(body, url, html_options = {})
  return '' if body.blank?

  link_to_html(markdown(body, pipeline: :single_line), url, html_options)
end


16
17
18
19
20
# File 'app/helpers/markup_helper.rb', line 16

def link_to_markdown_field(object, field, url, html_options = {})
  rendered_field = markdown_field(object, field)

  link_to_html(rendered_field, url, html_options)
end

#markdown(text, context = {}, postprocess = {}) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
# File 'app/helpers/markup_helper.rb', line 86

def markdown(text, context = {}, postprocess = {})
  return '' unless text.present?

  context[:project] ||= @project
  context[:group] ||= @group

  html = Markup::RenderingService.new(text, context: context,
    postprocess_context: postprocess_context.merge!(postprocess)).execute

  Hamlit::RailsHelpers.preserve(html)
end

#markdown_field(object, field, context = {}) ⇒ Object



98
99
100
101
102
103
104
105
106
# File 'app/helpers/markup_helper.rb', line 98

def markdown_field(object, field, context = {})
  object = object.for_display if object.respond_to?(:for_display)
  return '' unless object.present?

  redacted_field_html = object.try(:"redacted_#{field}_html")
  return redacted_field_html if redacted_field_html

  render_markdown_field(object, field, context)
end

#markup(file_name, text, context = {}) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
# File 'app/helpers/markup_helper.rb', line 108

def markup(file_name, text, context = {})
  context[:project] ||= @project
  context[:text_source] ||= :blob
  prepare_asciidoc_context(file_name, context)

  html = Markup::RenderingService
           .new(text, file_name: file_name, context: context, postprocess_context: postprocess_context)
           .execute

  Hamlit::RailsHelpers.preserve(html)
end

#render_wiki_content(wiki_page, context = {}) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'app/helpers/markup_helper.rb', line 120

def render_wiki_content(wiki_page, context = {})
  text = wiki_page.content
  return '' unless text.present?

  context = render_wiki_content_context(wiki_page.wiki, wiki_page, context)
  prepare_asciidoc_context(wiki_page.path, context)

  html = Markup::RenderingService
           .new(text, file_name: wiki_page.path, context: context, postprocess_context: postprocess_context)
           .execute

  Hamlit::RailsHelpers.preserve(html)
end