Merge pull request #8020 from mr-vinn/note-trunc-link
Improve event note display in dashboard and project activity views
This commit is contained in:
commit
4731d77bb2
3 changed files with 110 additions and 9 deletions
|
@ -136,9 +136,8 @@ module EventsHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def event_note(text)
|
def event_note(text)
|
||||||
text = first_line_in_markdown(text)
|
text = first_line_in_markdown(text, 150)
|
||||||
text = truncate(text, length: 150)
|
sanitize(text, tags: %w(a img b pre code p))
|
||||||
sanitize(markdown(text), tags: %w(a img b pre p))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def event_commit_title(message)
|
def event_commit_title(message)
|
||||||
|
|
|
@ -51,12 +51,14 @@ module GitlabMarkdownHelper
|
||||||
@markdown.render(text).html_safe
|
@markdown.render(text).html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
def first_line_in_markdown(text)
|
# Return the first line of +text+, up to +max_chars+, after parsing the line
|
||||||
line = text.split("\n").detect do |i|
|
# as Markdown. HTML tags in the parsed output are not counted toward the
|
||||||
i.present? && markdown(i).present?
|
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||||
end
|
# the tag contents are truncated without removing the closing tag.
|
||||||
line += '...' unless line.nil?
|
def first_line_in_markdown(text, max_chars = nil)
|
||||||
line
|
md = markdown(text).strip
|
||||||
|
|
||||||
|
truncate_visible(md, max_chars || md.length) if md.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_wiki_content(wiki_page)
|
def render_wiki_content(wiki_page)
|
||||||
|
@ -204,4 +206,52 @@ module GitlabMarkdownHelper
|
||||||
def correct_ref
|
def correct_ref
|
||||||
@ref ? @ref : "master"
|
@ref ? @ref : "master"
|
||||||
end
|
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.content = "#{node.content}..." if node.next_sibling
|
||||||
|
true
|
||||||
|
else
|
||||||
|
truncated
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
52
spec/helpers/events_helper_spec.rb
Normal file
52
spec/helpers/events_helper_spec.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe EventsHelper do
|
||||||
|
include ApplicationHelper
|
||||||
|
include GitlabMarkdownHelper
|
||||||
|
|
||||||
|
it 'should display one line of plain text without alteration' do
|
||||||
|
input = 'A short, plain note'
|
||||||
|
expect(event_note(input)).to match(input)
|
||||||
|
expect(event_note(input)).not_to match(/\.\.\.\z/)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should display inline code' do
|
||||||
|
input = 'A note with `inline code`'
|
||||||
|
expected = 'A note with <code>inline code</code>'
|
||||||
|
|
||||||
|
expect(event_note(input)).to match(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should truncate a note with multiple paragraphs' do
|
||||||
|
input = "Paragraph 1\n\nParagraph 2"
|
||||||
|
expected = 'Paragraph 1...'
|
||||||
|
|
||||||
|
expect(event_note(input)).to match(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should display the first line of a code block' do
|
||||||
|
input = "```\nCode block\nwith two lines\n```"
|
||||||
|
expected = '<pre><code class="">Code block...</code></pre>'
|
||||||
|
|
||||||
|
expect(event_note(input)).to match(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should truncate a single long line of text' do
|
||||||
|
text = 'The quick brown fox jumped over the lazy dog twice' # 50 chars
|
||||||
|
input = "#{text}#{text}#{text}#{text}" # 200 chars
|
||||||
|
expected = "#{text}#{text}".sub(/.{3}/, '...')
|
||||||
|
|
||||||
|
expect(event_note(input)).to match(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should preserve a link href when link text is truncated' do
|
||||||
|
text = 'The quick brown fox jumped over the lazy dog' # 44 chars
|
||||||
|
input = "#{text}#{text}#{text} " # 133 chars
|
||||||
|
link_url = 'http://example.com/foo/bar/baz' # 30 chars
|
||||||
|
input << link_url
|
||||||
|
expected_link_text = 'http://example...</a>'
|
||||||
|
|
||||||
|
expect(event_note(input)).to match(link_url)
|
||||||
|
expect(event_note(input)).to match(expected_link_text)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue