Коммит ed7d73d2 создал по автору gkats's avatar gkats Зафиксировано автором Sean McGivern
Просмотр файлов

Support rich references in links

Currently supports up to 1 rich reference verbosity level. Level 1
includes the referable title in the link text. The rich reference suffix
is '+'. More than 3 '+' characters are ingored.

So, `#123+` becomes a link with text "123 The issue title".

- Modified issue regex to account for rich references verbosity
- Modified IssueReferenceFilter to add a data-rich-ref-verbosity attribute
- Added a post processing pipeline filter (RichReferenceFilter) to deal with
rich references
владелец 90938e4b
......@@ -121,11 +121,13 @@ def self.reference_prefix
# Pattern used to extract `#123` issue references from text
#
# This pattern supports cross-project references.
# This pattern supports cross-project references. Takes rich reference
# suffixes (+) into consideration, so it matches `#123+++`.
def self.reference_pattern
@reference_pattern ||= %r{
(#{Project.reference_pattern})?
#{Regexp.escape(reference_prefix)}(?<issue>\d+)
(?<rich_ref_verbosity>#{Regexp.escape(Banzai::Filter::RichReferenceFilter::VERBOSITY_CHAR)}{1,3})?
}x
end
......
---
title: "Support rich references in links"
merge_request: 7313
author: Giannis Katsanos
......@@ -152,8 +152,6 @@ def object_link_filter(text, pattern, link_content: nil)
title = object_link_title(object)
klass = reference_class(object_sym)
data = data_attributes_for(link_content || match, project, object)
if matches.names.include?("url") && matches[:url]
url = matches[:url]
else
......@@ -161,8 +159,11 @@ def object_link_filter(text, pattern, link_content: nil)
end
content = link_content || object_link_text(object, matches)
rich_ref_verbosity = rich_ref_verbosity_for(matches)
data = data_attributes_for(link_content || match, project, object, rich_ref_verbosity)
%(<a href="#{url}" #{data}
%(<a href="#{url}" #{data} #{}
title="#{escape_once(title)}"
class="#{klass}">#{content}</a>)
else
......@@ -171,12 +172,20 @@ def object_link_filter(text, pattern, link_content: nil)
end
end
def data_attributes_for(text, project, object)
data_attribute(
original: text,
project: project.id,
def data_attributes_for(text, project, object, rich_ref_verbosity)
attributes = {
original: text,
project: project.id,
rich_ref_verbosity: rich_ref_verbosity,
object_sym => object.id
)
}
data_attribute(attributes.compact)
end
def rich_ref_verbosity_for(matches)
rich_ref_verbosity = matches.names.include?('rich_ref_verbosity') && matches[:rich_ref_verbosity]
{ rich_ref_verbosity: rich_ref_verbosity.length } unless rich_ref_verbosity.blank?
end
def object_link_text_extras(object, matches)
......
module Banzai
module Filter
# HTML filter to support rich references in links.
#
# Appends information on the link text depending on the verbosity
# level. It is expected to run in a post-processing pipeline.
class RichReferenceFilter < HTML::Pipeline::Filter
VERBOSITY_CHAR = '+'
def call
links.each do |link|
handle_reference_verbosity_for(link)
end
doc
end
private
def links
@links ||= doc.css('a[data-rich-ref-verbosity]')
end
def handle_reference_verbosity_for(link)
verbosity = link.attr('data-rich-ref-verbosity').to_i
if verbosity > 0
link.content = "#{link.text} #{link.attr('title')}"
end
if verbosity > 1
# We support up to 3 levels of verbosity, but for now we implement
# only 1. Restore the missing '+' characters.
# This will not be needed if we support verbosity up to 3.
missing = VERBOSITY_CHAR * (verbosity - 1)
link.add_next_sibling(missing)
end
end
end
end
end
......@@ -4,7 +4,8 @@ class PostProcessPipeline < BasePipeline
def self.filters
FilterArray[
Filter::RelativeLinkFilter,
Filter::RedactorFilter
Filter::RedactorFilter,
Filter::RichReferenceFilter
]
end
......
......@@ -3,7 +3,8 @@ module Pipeline
class RelativeLinkPipeline < BasePipeline
def self.filters
FilterArray[
Filter::RelativeLinkFilter
Filter::RelativeLinkFilter,
Filter::RichReferenceFilter
]
end
end
......
......@@ -114,6 +114,41 @@ def helper
expect(link).to eq(href)
end
it 'processes references with "+" (rich reference verbosity) suffix' do
doc = reference_filter("See #{reference}+")
expect(doc.css('a').first.attr('href')).
to eq helper.url_for_issue(issue.iid, project)
end
it 'strips the "+" rich reference verbosity suffix from the link text' do
doc = reference_filter("See #{reference}+")
expect(doc.text).not_to include('+')
end
it 'adds a data-rich-ref-verbosity attribute for "+" suffix' do
doc = reference_filter("See #{reference}+")
link = doc.css('a').first
expect(link.attr('data-rich-ref-verbosity')).to eq('1')
end
it 'supports up to 3 "+" characters for rich reference verbosity' do
doc = reference_filter("See #{reference}+++")
link = doc.css('a').first
expect(link.attr('data-rich-ref-verbosity')).to eq('3')
expect(doc.text).not_to include('+')
doc = reference_filter("See #{reference}++++")
link = doc.css('a').first
expect(link.attr('data-rich-ref-verbosity')).to eq('3')
expect(doc.text).to match(/\+{1}/)
end
it 'does not add a data-rich-ref-verbosity attribute if there\'s no "+" suffix' do
doc = reference_filter("See #{reference}")
link = doc.css('a').first
expect(link.to_html).not_to include('data-rich-ref-verbosity')
end
end
context 'cross-project reference' do
......
require 'spec_helper'
describe Banzai::Filter::RichReferenceFilter, lib: true do
include FilterSpecHelper
describe '#call' do
context 'with data-rich-ref-verbosity of 1' do
def doc(title)
Nokogiri::HTML.fragment(
"<a href='#' data-rich-ref-verbosity='1' title='#{title}'>#1</a>"
)
end
it 'appends the issue title' do
title = 'An issue title'
expect(filter(doc(title)).at_css('a').text).to include(title)
end
context 'but no title' do
it 'does not modify the document' do
document = doc(nil)
expect(filter(document)).to eq(document)
end
end
end
context 'with data-rich-ref-verbosity of 0' do
it 'does not modify the document' do
doc = Nokogiri::HTML.fragment("<a href='#' data-rich-ref-verbosity='0'>#1</a>")
expect(filter(doc)).to eq(doc)
end
end
context 'with no data-rich-ref-verbosity' do
it 'does not modify the document' do
doc = Nokogiri::HTML.fragment("<a href='#'>#1+</a>")
expect(filter(doc)).to eq(doc)
end
end
context 'with no <a> tag in the document' do
it 'does not modify the document' do
doc = Nokogiri::HTML.fragment('<p>Some text</p>')
expect(filter(doc)).to eq(doc)
end
end
context 'with data-rich-ref-verbosity of 2' do
let(:doc) do
Nokogiri::HTML.fragment("<a href='#' data-rich-ref-verbosity='2' title='#{title}'>#1</a>")
end
let(:title) { 'An issue title' }
it 'appends the issue title' do
expect(filter(doc).at_css('a').text).to include(title)
end
it 'adds an extra "+"' do
expect(filter(doc).to_html).to include('+')
end
end
context 'with data-rich-ref-verbosity of 3' do
let(:doc) do
Nokogiri::HTML.fragment("<a href='#' data-rich-ref-verbosity='3' title='#{title}'>#1</a>")
end
let(:title) { 'An issue title' }
it 'appends the issue title' do
expect(filter(doc).at_css('a').text).to include(title)
end
it 'adds two extra "+"' do
expect(filter(doc).to_html).to include('++')
end
end
context 'with more than one links with data-rich-ref-verbosity' do
let(:doc) do
Nokogiri::HTML.fragment(
"<a href='#' title='first title'>#1</a> but also " +
"<a href='#' data-rich-ref-verbosity='1' title='second title'>#2</a> and " +
"<a href='#' data-rich-ref-verbosity='1' title='third title'>#3</a>"
)
end
it 'appends the issue title for all links with data-rich-ref-verbosity' do
html = filter(doc).to_html
expect(html).not_to include('#1 first title')
expect(html).to include('#2 second title')
expect(html).to include('#3 third title')
end
end
context 'with text attribute following a rich-ref link and rich-ref-verbosity > 1' do
let(:doc) do
Nokogiri::HTML.fragment(
"<a href='#' data-rich-ref-verbosity='#{rich_ref_verbosity}' title='a title'>#1</a>Something else here."
)
end
let(:rich_ref_verbosity) { 2 }
it 'adds an extra node with missing "+"s' do
expect(filter(doc).to_html).to include('+' * (rich_ref_verbosity - 1))
end
end
context 'with non-text attribute following a rich-ref link and rich-ref-verbosity > 1' do
let(:doc) do
Nokogiri::HTML.fragment(
"<a href='#' data-rich-ref-verbosity='2' title='a title'>#1</a><a href='#'>#2</a>"
)
end
it 'adds a text node for extra "+"s' do
text = filter(doc)
expect(text.to_html).to include('</a>+<a href="#">#2</a>')
end
end
end
end
Поддерживает Markdown
0% или .
You are about to add 0 people to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Пожалуйста, зарегистрируйтесь или чтобы прокомментировать