Module: MarkupHelper

Extended by:
MarkupHelper
Includes:
ActionView::Context, ActionView::Helpers::TextHelper
Included in:
API::Entities::CommitWithLink, AppearancesHelper, Emails::ServiceDesk, ForkNamespaceEntity, Gitlab::TreeSummary, GroupChildEntity, MarkupHelper, MergeRequestPresenter
Defined in:
app/helpers/markup_helper.rb

Instance Method Summary collapse

Instance Method Details

#asciidoc?(filename) ⇒ Boolean

Returns:

  • (Boolean)

21
22
23
# File 'app/helpers/markup_helper.rb', line 21

def asciidoc?(filename)
  Gitlab::MarkupHelper.asciidoc?(filename)
end

#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


166
167
168
169
170
171
172
# File 'app/helpers/markup_helper.rb', line 166

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.


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/helpers/markup_helper.rb', line 78

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)
  tags << 'img' if options[:allow_images]

  text = truncate_visible(md, max_chars || md.length)
  text = prepare_for_rendering(text, markdown_field_render_context(object, attribute, options))
  text = sanitize(
    text,
    tags: tags,
    attributes: Rails::Html::WhiteListSanitizer.allowed_attributes +
        %w(style data-src data-name data-unicode-version data-iid data-project-path data-mr-title data-html)
  )

  # since <img> tags are stripped, this can leave empty <a> tags hanging around
  # (as our markdown wraps images in links)
  options[:allow_images] ? text : strip_empty_link_tags(text).html_safe
end

#gitlab_markdown?(filename) ⇒ Boolean

Returns:

  • (Boolean)

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

def gitlab_markdown?(filename)
  Gitlab::MarkupHelper.gitlab_markdown?(filename)
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>”).


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/helpers/markup_helper.rb', line 45

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(…), …).


26
27
28
29
30
# File 'app/helpers/markup_helper.rb', line 26

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

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

32
33
34
35
36
# File 'app/helpers/markup_helper.rb', line 32

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 = {}) ⇒ Object


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

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

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

  html = markdown_unsafe(text, context)
  prepare_for_rendering(html, context)
end

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


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

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


119
120
121
122
123
# File 'app/helpers/markup_helper.rb', line 119

def markup(file_name, text, context = {})
  context[:project] ||= @project
  html = context.delete(:rendered) || markup_unsafe(file_name, text, context)
  prepare_for_rendering(html, context)
end

#markup?(filename) ⇒ Boolean

Returns:

  • (Boolean)

13
14
15
# File 'app/helpers/markup_helper.rb', line 13

def markup?(filename)
  Gitlab::MarkupHelper.markup?(filename)
end

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


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'app/helpers/markup_helper.rb', line 134

def markup_unsafe(file_name, text, context = {})
  return '' unless text.present?

  if gitlab_markdown?(file_name)
    markdown_unsafe(text, context)
  elsif asciidoc?(file_name)
    asciidoc_unsafe(text, context)
  elsif plain?(file_name)
    plain_unsafe(text)
  else
    other_markup_unsafe(file_name, text, context)
  end
rescue StandardError => e
  Gitlab::ErrorTracking.track_exception(e, project_id: @project&.id, file_name: file_name)

  simple_format(text)
end

#plain?(filename) ⇒ Boolean

Returns:

  • (Boolean)

9
10
11
# File 'app/helpers/markup_helper.rb', line 9

def plain?(filename)
  Gitlab::MarkupHelper.plain?(filename)
end

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


125
126
127
128
129
130
131
132
# File 'app/helpers/markup_helper.rb', line 125

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

  html = markup_unsafe(wiki_page.path, text, render_wiki_content_context(@wiki, wiki_page, context))

  prepare_for_rendering(html, context)
end