2018-08-10 11:41:01 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-06-30 09:17:03 +00:00
|
|
|
module Banzai
|
|
|
|
module Filter
|
|
|
|
# HTML filter that replaces project references with links.
|
|
|
|
class ProjectReferenceFilter < ReferenceFilter
|
|
|
|
self.reference_type = :project
|
|
|
|
|
2018-07-03 16:54:59 +00:00
|
|
|
# Public: Find `namespace/project>` project references in text
|
2018-06-30 09:17:03 +00:00
|
|
|
#
|
|
|
|
# ProjectReferenceFilter.references_in(text) do |match, project|
|
|
|
|
# "<a href=...>#{project}></a>"
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# text - String text to search.
|
|
|
|
#
|
|
|
|
# Yields the String match, and the String project name.
|
|
|
|
#
|
|
|
|
# Returns a String replaced with the return of the block.
|
|
|
|
def self.references_in(text)
|
|
|
|
text.gsub(Project.markdown_reference_pattern) do |match|
|
|
|
|
yield match, "#{$~[:namespace]}/#{$~[:project]}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def call
|
|
|
|
ref_pattern = Project.markdown_reference_pattern
|
|
|
|
ref_pattern_start = /\A#{ref_pattern}\z/
|
|
|
|
|
2020-07-15 06:09:35 +00:00
|
|
|
nodes.each_with_index do |node, index|
|
2018-06-30 09:17:03 +00:00
|
|
|
if text_node?(node)
|
2020-07-15 06:09:35 +00:00
|
|
|
replace_text_when_pattern_matches(node, index, ref_pattern) do |content|
|
2018-06-30 09:17:03 +00:00
|
|
|
project_link_filter(content)
|
|
|
|
end
|
|
|
|
elsif element_node?(node)
|
|
|
|
yield_valid_link(node) do |link, inner_html|
|
|
|
|
if link =~ ref_pattern_start
|
2020-07-15 06:09:35 +00:00
|
|
|
replace_link_node_with_href(node, index, link) do
|
2018-06-30 09:17:03 +00:00
|
|
|
project_link_filter(link, link_content: inner_html)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
doc
|
|
|
|
end
|
|
|
|
|
2018-07-03 04:45:56 +00:00
|
|
|
# Replace `namespace/project>` project references in text with links to the referenced
|
2018-06-30 09:17:03 +00:00
|
|
|
# project page.
|
|
|
|
#
|
|
|
|
# text - String text to replace references in.
|
|
|
|
# link_content - Original content of the link being replaced.
|
|
|
|
#
|
2018-07-03 04:45:56 +00:00
|
|
|
# Returns a String with `namespace/project>` references replaced with links. All links
|
2018-06-30 09:17:03 +00:00
|
|
|
# have `gfm` and `gfm-project` class names attached for styling.
|
|
|
|
def project_link_filter(text, link_content: nil)
|
2018-07-02 19:39:39 +00:00
|
|
|
self.class.references_in(text) do |match, project_path|
|
|
|
|
cached_call(:banzai_url_for_object, match, path: [Project, project_path.downcase]) do
|
|
|
|
if project = projects_hash[project_path.downcase]
|
2018-06-30 09:17:03 +00:00
|
|
|
link_to_project(project, link_content: link_content) || match
|
|
|
|
else
|
|
|
|
match
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-06-30 13:19:07 +00:00
|
|
|
# Returns a Hash containing all Project objects for the project
|
2018-06-30 09:17:03 +00:00
|
|
|
# references in the current document.
|
|
|
|
#
|
2018-06-30 13:19:07 +00:00
|
|
|
# The keys of this Hash are the project paths, the values the
|
|
|
|
# corresponding Project objects.
|
2018-06-30 09:17:03 +00:00
|
|
|
def projects_hash
|
2018-07-03 15:56:28 +00:00
|
|
|
@projects ||= Project.eager_load(:route, namespace: [:route])
|
2018-07-03 04:48:49 +00:00
|
|
|
.where_full_path_in(projects)
|
2018-06-30 09:17:03 +00:00
|
|
|
.index_by(&:full_path)
|
|
|
|
.transform_keys(&:downcase)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Returns all projects referenced in the current document.
|
|
|
|
def projects
|
|
|
|
refs = Set.new
|
|
|
|
|
|
|
|
nodes.each do |node|
|
|
|
|
node.to_html.scan(Project.markdown_reference_pattern) do
|
|
|
|
refs << "#{$~[:namespace]}/#{$~[:project]}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
refs.to_a
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def urls
|
|
|
|
Gitlab::Routing.url_helpers
|
|
|
|
end
|
|
|
|
|
|
|
|
def link_class
|
|
|
|
reference_class(:project)
|
|
|
|
end
|
|
|
|
|
|
|
|
def link_to_project(project, link_content: nil)
|
|
|
|
url = urls.project_url(project, only_path: context[:only_path])
|
|
|
|
data = data_attribute(project: project.id)
|
2020-01-29 12:09:08 +00:00
|
|
|
content = link_content || project.to_reference
|
2018-06-30 09:17:03 +00:00
|
|
|
|
|
|
|
link_tag(url, data, content, project.name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def link_tag(url, data, link_content, title)
|
|
|
|
%(<a href="#{url}" #{data} class="#{link_class}" title="#{escape_once(title)}">#{link_content}</a>)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|