diff options
Diffstat (limited to 'app/helpers/gitlab_markdown_helper.rb')
-rw-r--r-- | app/helpers/gitlab_markdown_helper.rb | 94 |
1 files changed, 69 insertions, 25 deletions
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 7bcc011fd5f..a801d3b10aa 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -1,5 +1,8 @@ +require 'nokogiri' + module GitlabMarkdownHelper include Gitlab::Markdown + include PreferencesHelper # Use this in places where you would normally use link_to(gfm(...), ...). # @@ -21,36 +24,44 @@ module GitlabMarkdownHelper gfm_body = gfm(escaped_body, {}, html_options) - gfm_body.gsub!(%r{<a.*?>.*?</a>}m) do |match| - "</a>#{match}#{link_to("", url, html_options)[0..-5]}" # "</a>".length +1 + fragment = Nokogiri::XML::DocumentFragment.parse(gfm_body) + 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 pure + # text, wrapping anything found in the requested link + fragment.children.each do |node| + next unless node.text? + node.replace(link_to(node.text, url, html_options)) + end end - link_to(gfm_body.html_safe, url, html_options) + fragment.to_html.html_safe end + MARKDOWN_OPTIONS = { + no_intra_emphasis: true, + tables: true, + fenced_code_blocks: true, + strikethrough: true, + lax_spacing: true, + space_after_headers: true, + superscript: true, + footnotes: true + }.freeze + def markdown(text, options={}) unless @markdown && options == @options @options = options - options.merge!( - # Handled further down the line by Gitlab::Markdown::SanitizationFilter - escape_html: false - ) - # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options) # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use - @markdown = Redcarpet::Markdown.new(rend, - no_intra_emphasis: true, - tables: true, - fenced_code_blocks: true, - strikethrough: true, - lax_spacing: true, - space_after_headers: true, - superscript: true, - footnotes: true - ) + @markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS) end @markdown.render(text).html_safe @@ -87,6 +98,29 @@ module GitlabMarkdownHelper end end + MARKDOWN_TIPS = [ + "End a line with two or more spaces for a line-break, or soft-return", + "Inline code can be denoted by `surrounding it with backticks`", + "Blocks of code can be denoted by three backticks ``` or four leading spaces", + "Emoji can be added by :emoji_name:, for example :thumbsup:", + "Notify other participants using @user_name", + "Notify a specific group using @group_name", + "Notify the entire team using @all", + "Reference an issue using a hash, for example issue #123", + "Reference a merge request using an exclamation point, for example MR !123", + "Italicize words or phrases using *asterisks* or _underscores_", + "Bold words or phrases using **double asterisks** or __double underscores__", + "Strikethrough words or phrases using ~~two tildes~~", + "Make a bulleted list using + pluses, - minuses, or * asterisks", + "Denote blockquotes using > 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 + "Tip: #{MARKDOWN_TIPS.sample}" + end + private # Return +text+, truncated to +max_chars+ characters, excluding any HTML @@ -135,15 +169,25 @@ module GitlabMarkdownHelper 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) - path = project.path_with_namespace - - if entity.kind_of?(Issue) - [path, entity.iid].join('#') - elsif entity.kind_of?(MergeRequest) - [path, entity.iid].join('!') + if entity.respond_to?(:to_reference) + "#{project.to_reference}#{entity.to_reference}" else - raise 'Not supported type' + '' end end end |