Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/helpers/gitlab_markdown_helper.rb37
-rw-r--r--app/views/events/_commit.html.haml2
-rw-r--r--app/views/projects/commit/_commit_box.html.haml4
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/_open.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/repositories/_feed.html.haml2
-rw-r--r--lib/gitlab/markdown.rb236
-rw-r--r--lib/gitlab/markdown/markdown_filter.rb39
-rw-r--r--lib/gitlab/markdown/relative_link_filter.rb2
-rw-r--r--lib/gitlab/markdown/sanitization_filter.rb6
-rw-r--r--lib/gitlab/reference_extractor.rb20
14 files changed, 181 insertions, 177 deletions
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 65813482120..c6fff1b8ecf 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -20,7 +20,7 @@ module GitlabMarkdownHelper
end
user = current_user if defined?(current_user)
- gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: user)
+ gfm_body = Gitlab::Markdown.render(escaped_body, project: @project, current_user: user, pipeline: :single_line)
fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a'
@@ -48,37 +48,20 @@ module GitlabMarkdownHelper
def markdown(text, context = {})
return "" unless text.present?
- context.reverse_merge!(
- path: @path,
- pipeline: :default,
- project: @project,
- project_wiki: @project_wiki,
- ref: @ref
- )
-
- user = current_user if defined?(current_user)
-
+ context[:project] ||= @project
+
html = Gitlab::Markdown.render(text, context)
- Gitlab::Markdown.post_process(html, pipeline: context[:pipeline], project: @project, user: user)
- end
- # TODO (rspeicher): Remove all usages of this helper and just call `markdown`
- # with a custom pipeline depending on the content being rendered
- def gfm(text, options = {})
- return "" unless text.present?
+ context.merge!(
+ current_user: (current_user if defined?(current_user)),
- options.reverse_merge!(
- path: @path,
- pipeline: :default,
- project: @project,
- project_wiki: @project_wiki,
- ref: @ref
+ # RelativeLinkFilter
+ requested_path: @path,
+ project_wiki: @project_wiki,
+ ref: @ref
)
- user = current_user if defined?(current_user)
-
- html = Gitlab::Markdown.gfm(text, options)
- Gitlab::Markdown.post_process(html, pipeline: options[:pipeline], project: @project, user: user)
+ Gitlab::Markdown.post_process(html, context)
end
def asciidoc(text)
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index ad63841ccf3..4ba8b84fd92 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -2,4 +2,4 @@
.commit-row-title
= link_to truncate_sha(commit[:id]), namespace_project_commit_path(project.namespace, project, commit[:id]), class: "commit_short_id", alt: ''
·
- = gfm event_commit_title(commit[:message]), project: project
+ = markdown event_commit_title(commit[:message]), project: project, pipeline: :single_line
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index fbf0a9ec0c3..f3be1da8428 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -50,10 +50,10 @@
.commit-box.gray-content-block.middle-block
%h3.commit-title
- = gfm escape_once(@commit.title)
+ = markdown escape_once(@commit.title), pipeline: :single_line
- if @commit.description.present?
%pre.commit-description
- = preserve(gfm(escape_once(@commit.description)))
+ = preserve(markdown(escape_once(@commit.description), pipeline: :single_line))
:coffeescript
$(".commit-info-row.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}")
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index cddd5aa3a83..9e0b536bb4b 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -32,7 +32,7 @@
- if commit.description?
.commit-row-description.js-toggle-content
%pre
- = preserve(gfm(escape_once(commit.description)))
+ = preserve(markdown(escape_once(commit.description), pipeline: :single_line))
.commit-row-info
= commit_author_link(commit, avatar: true, size: 24)
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 5cb814c9ea8..3233c6884cc 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -37,7 +37,7 @@
.gray-content-block.middle-block
%h2.issue-title
- = gfm escape_once(@issue.title)
+ = markdown escape_once(@issue.title), pipeline: :single_line
%div
- if @issue.description.present?
.description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index b4f62a75890..448230a377c 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,6 +1,6 @@
.gray-content-block.middle-block
%h2.issue-title
- = gfm escape_once(@merge_request.title)
+ = markdown escape_once(@merge_request.title), pipeline: :single_line
%div
- if @merge_request.description.present?
diff --git a/app/views/projects/merge_requests/widget/_open.html.haml b/app/views/projects/merge_requests/widget/_open.html.haml
index 0aad9bb3e88..8629129c0b1 100644
--- a/app/views/projects/merge_requests/widget/_open.html.haml
+++ b/app/views/projects/merge_requests/widget/_open.html.haml
@@ -24,4 +24,4 @@
%i.fa.fa-check
Accepting this merge request will close #{"issue".pluralize(@closes_issues.size)}
= succeed '.' do
- != gfm(issues_sentence(@closes_issues))
+ != markdown issues_sentence(@closes_issues), pipeline: :gfm
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 4eeb0621e52..302410765fc 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -31,7 +31,7 @@
%span All issues for this milestone are closed. You may close milestone now.
%h3.issue-title
- = gfm escape_once(@milestone.title)
+ = markdown escape_once(@milestone.title), pipeline: :single_line
%div
- if @milestone.description.present?
.description
diff --git a/app/views/projects/repositories/_feed.html.haml b/app/views/projects/repositories/_feed.html.haml
index f3526ad0747..6ca919f7f80 100644
--- a/app/views/projects/repositories/_feed.html.haml
+++ b/app/views/projects/repositories/_feed.html.haml
@@ -12,7 +12,7 @@
= link_to namespace_project_commits_path(@project.namespace, @project, commit.id) do
%code= commit.short_id
= image_tag avatar_icon(commit.author_email), class: "", width: 16, alt: ''
- = gfm escape_once(truncate(commit.title, length: 40))
+ = markdown escape_once(truncate(commit.title, length: 40)), pipeline: :single_line
%td
%span.pull-right.cgray
= time_ago_with_tooltip(commit.committed_date)
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index d5b0060dd56..773ebddba2b 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -19,51 +19,15 @@ module Gitlab
# context - Hash of context options passed to our HTML Pipeline
#
# Returns an HTML-safe String
- def self.render(markdown, context = {})
- html = renderer.render(markdown)
- html = gfm(html, context)
+ def self.render(text, context = {})
+ pipeline = context[:pipeline] || :full
- html.html_safe
- end
+ html_pipeline = html_pipelines[pipeline]
- # Convert a Markdown String into HTML without going through the HTML
- # Pipeline.
- #
- # Note that because the pipeline is skipped, SanitizationFilter is as well.
- # Do not output the result of this method to the user.
- #
- # markdown - Markdown String
- #
- # Returns a String
- def self.render_without_gfm(markdown)
- renderer.render(markdown)
- end
+ transformers = get_context_transformers(pipeline)
+ context = transformers.reduce(context) { |context, transformer| transformer.call(context) }
- # Perform post-processing on an HTML String
- #
- # This method is used to perform state-dependent changes to a String of
- # HTML, such as removing references that the current user doesn't have
- # permission to make (`RedactorFilter`).
- #
- # html - String to process
- # options - Hash of options to customize output
- # :pipeline - Symbol pipeline type
- # :project - Project
- # :user - User object
- #
- # Returns an HTML-safe String
- def self.post_process(html, options)
- context = {
- project: options[:project],
- current_user: options[:user]
- }
- doc = post_processor.to_document(html, context)
-
- if options[:pipeline] == :atom
- doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
- else
- doc.to_html
- end.html_safe
+ html_pipeline.to_html(text, context)
end
# Provide autoload paths for filters to prevent a circular dependency error
@@ -75,6 +39,7 @@ module Gitlab
autoload :ExternalLinkFilter, 'gitlab/markdown/external_link_filter'
autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter'
autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter'
+ autoload :MarkdownFilter, 'gitlab/markdown/markdown_filter'
autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter'
autoload :RedactorFilter, 'gitlab/markdown/redactor_filter'
autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter'
@@ -85,98 +50,38 @@ module Gitlab
autoload :TaskListFilter, 'gitlab/markdown/task_list_filter'
autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter'
- # Public: Parse the provided HTML with GitLab-Flavored Markdown
+ # Perform post-processing on an HTML String
+ #
+ # This method is used to perform state-dependent changes to a String of
+ # HTML, such as removing references that the current user doesn't have
+ # permission to make (`RedactorFilter`).
#
- # html - HTML String
- # options - A Hash of options used to customize output (default: {})
- # :no_header_anchors - Disable header anchors in TableOfContentsFilter
- # :path - Current path String
- # :pipeline - Symbol pipeline type
- # :project - Current Project object
- # :project_wiki - Current ProjectWiki object
- # :ref - Current ref String
+ # html - String to process
+ # context - Hash of options to customize output
+ # :pipeline - Symbol pipeline type
+ # :project - Project
+ # :user - User object
#
# Returns an HTML-safe String
- def self.gfm(html, options = {})
- return '' unless html.present?
-
- @pipeline ||= HTML::Pipeline.new(filters)
-
- context = {
- # SanitizationFilter
- pipeline: options[:pipeline],
-
- # EmojiFilter
- asset_host: Gitlab::Application.config.asset_host,
- asset_root: Gitlab.config.gitlab.base_url,
-
- # ReferenceFilter
- only_path: only_path_pipeline?(options[:pipeline]),
- project: options[:project],
-
- # RelativeLinkFilter
- project_wiki: options[:project_wiki],
- ref: options[:ref],
- requested_path: options[:path],
-
- # TableOfContentsFilter
- no_header_anchors: options[:no_header_anchors]
- }
+ def self.post_process(html, context)
+ doc = html_pipelines[:post_process].to_document(html, context)
- @pipeline.to_html(html, context).html_safe
- end
-
- private
-
- # Check if a pipeline enables the `only_path` context option
- #
- # Returns Boolean
- def self.only_path_pipeline?(pipeline)
- case pipeline
- when :atom, :email
- false
+ if context[:xhtml]
+ doc.to_html(save_with: Nokogiri::XML::Node::SaveOptions::AS_XHTML)
else
- true
- end
- end
-
- def self.redcarpet_options
- # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
- @redcarpet_options ||= {
- fenced_code_blocks: true,
- footnotes: true,
- lax_spacing: true,
- no_intra_emphasis: true,
- space_after_headers: true,
- strikethrough: true,
- superscript: true,
- tables: true
- }.freeze
- end
-
- def self.renderer
- @markdown ||= begin
- renderer = Redcarpet::Render::HTML.new
- Redcarpet::Markdown.new(renderer, redcarpet_options)
- end
- end
-
- def self.post_processor
- @post_processor ||= HTML::Pipeline.new([Gitlab::Markdown::RedactorFilter])
+ doc.to_html
+ end.html_safe
end
- # Filters used in our pipeline
- #
- # SanitizationFilter should come first so that all generated reference HTML
- # goes through untouched.
- #
- # See https://github.com/jch/html-pipeline#filters for more filters.
- def self.filters
- [
+ private
+ FILTERS = {
+ plain_markdown: [
+ Gitlab::Markdown::MarkdownFilter
+ ],
+ gfm: [
Gitlab::Markdown::SyntaxHighlightFilter,
Gitlab::Markdown::SanitizationFilter,
- Gitlab::Markdown::RelativeLinkFilter,
Gitlab::Markdown::EmojiFilter,
Gitlab::Markdown::TableOfContentsFilter,
Gitlab::Markdown::AutolinkFilter,
@@ -192,7 +97,90 @@ module Gitlab
Gitlab::Markdown::LabelReferenceFilter,
Gitlab::Markdown::TaskListFilter
+ ],
+
+ full: [:plain_markdown, :gfm],
+ atom: :full,
+ email: :full,
+ description: :full,
+ single_line: :gfm,
+
+ post_process: [
+ Gitlab::Markdown::RelativeLinkFilter,
+ Gitlab::Markdown::RedactorFilter
]
+ }
+
+ CONTEXT_TRANSFORMERS = {
+ gfm: {
+ only_path: true,
+
+ # EmojiFilter
+ asset_host: Gitlab::Application.config.asset_host,
+ asset_root: Gitlab.config.gitlab.base_url
+ },
+ full: :gfm,
+
+ atom: [
+ :full,
+ {
+ only_path: false,
+ xhtml: true
+ }
+ ],
+ email: [
+ :full,
+ {
+ only_path: false
+ }
+ ],
+ description: [
+ :full,
+ {
+ # SanitizationFilter
+ inline_sanitization: true
+ }
+ ],
+ single_line: :gfm,
+
+ post_process: {
+ post_process: true
+ }
+ }
+
+ def self.html_pipelines
+ @html_pipelines ||= Hash.new do |hash, pipeline|
+ filters = get_filters(pipeline)
+ HTML::Pipeline.new(filters)
+ end
+ end
+
+ def self.get_filters(pipelines)
+ Array.wrap(pipelines).flat_map do |pipeline|
+ case pipeline
+ when Class
+ pipeline
+ when Symbol
+ get_filters(FILTERS[pipeline])
+ when Array
+ get_filters(pipeline)
+ end
+ end.compact
+ end
+
+ def self.get_context_transformers(pipelines)
+ Array.wrap(pipelines).flat_map do |pipeline|
+ case pipeline
+ when Hash
+ ->(context) { context.merge(pipeline) }
+ when Proc
+ pipeline
+ when Symbol
+ get_context_transformers(CONTEXT_TRANSFORMERS[pipeline])
+ when Array
+ get_context_transformers(pipeline)
+ end
+ end.compact
end
end
end
diff --git a/lib/gitlab/markdown/markdown_filter.rb b/lib/gitlab/markdown/markdown_filter.rb
new file mode 100644
index 00000000000..921e2a0794e
--- /dev/null
+++ b/lib/gitlab/markdown/markdown_filter.rb
@@ -0,0 +1,39 @@
+module Gitlab
+ module Markdown
+ class MarkdownFilter < HTML::Pipeline::TextFilter
+ def initialize(text, context = nil, result = nil)
+ super text, context, result
+ @text = @text.gsub "\r", ''
+ end
+
+ def call
+ html = self.class.renderer.render(@text)
+ html.rstrip!
+ html
+ end
+
+ private
+
+ def self.redcarpet_options
+ # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
+ @redcarpet_options ||= {
+ fenced_code_blocks: true,
+ footnotes: true,
+ lax_spacing: true,
+ no_intra_emphasis: true,
+ space_after_headers: true,
+ strikethrough: true,
+ superscript: true,
+ tables: true
+ }.freeze
+ end
+
+ def self.renderer
+ @renderer ||= begin
+ renderer = Redcarpet::Render::HTML.new
+ Redcarpet::Markdown.new(renderer, redcarpet_options)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb
index 6ee3d1ce039..3e9909d2f33 100644
--- a/lib/gitlab/markdown/relative_link_filter.rb
+++ b/lib/gitlab/markdown/relative_link_filter.rb
@@ -16,7 +16,7 @@ module Gitlab
def call
return doc unless linkable_files?
- doc.search('a').each do |el|
+ doc.search('a:not(.gfm)').each do |el|
process_link_attr el.attribute('href')
end
diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb
index e368de7d848..550dfafca85 100644
--- a/lib/gitlab/markdown/sanitization_filter.rb
+++ b/lib/gitlab/markdown/sanitization_filter.rb
@@ -11,7 +11,7 @@ module Gitlab
def whitelist
# Descriptions are more heavily sanitized, allowing only a few elements.
# See http://git.io/vkuAN
- if pipeline == :description
+ if context[:inline_sanitization]
whitelist = LIMITED
whitelist[:elements] -= %w(pre code img ol ul li)
else
@@ -25,10 +25,6 @@ module Gitlab
private
- def pipeline
- context[:pipeline] || :default
- end
-
def customized?(transformers)
transformers.last.source_location[0] == __FILE__
end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 66016ecc877..633c988d025 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -13,7 +13,8 @@ module Gitlab
def analyze(text)
references.clear
- @text = Gitlab::Markdown.render_without_gfm(text)
+
+ @document = Gitlab::Markdown.render(text, project: project)
end
%i(user label issue merge_request snippet commit commit_range).each do |type|
@@ -44,20 +45,13 @@ module Gitlab
filter = Gitlab::Markdown.const_get(klass)
context = {
- project: project,
- current_user: current_user,
-
- # We don't actually care about the links generated
- only_path: true,
- ignore_blockquotes: true,
-
- # ReferenceGathererFilter
+ project: project,
+ current_user: current_user,
load_lazy_references: false,
reference_filter: filter
}
- pipeline = HTML::Pipeline.new([filter, Gitlab::Markdown::ReferenceGathererFilter], context)
- result = pipeline.call(@text)
+ result = self.class.pipeline.call(@document, context)
values = result[:references][filter_type].uniq
@@ -67,5 +61,9 @@ module Gitlab
values
end
+
+ def self.pipeline
+ @pipeline ||= HTML::Pipeline.new([Gitlab::Markdown::ReferenceGathererFilter])
+ end
end
end