summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2015-05-13 14:26:39 +0300
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2015-05-13 14:26:39 +0300
commit63403019d286ae5dc7ff2481f8a948da96057489 (patch)
tree711eafd76030433ef6ba6dfcb1887c1902b095a9 /lib
parentf32a045ef41688859732abfcdc2a2030387be78f (diff)
parent740716afd16e6487c965caf9c2f63e99fc78c076 (diff)
downloadgitlab-ce-63403019d286ae5dc7ff2481f8a948da96057489.tar.gz
Merge branch 'master' of github.com:gitlabhq/gitlabhq
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/markdown.rb9
-rw-r--r--lib/gitlab/markdown/relative_link_filter.rb114
-rw-r--r--lib/redcarpet/render/gitlab_html.rb4
3 files changed, 122 insertions, 5 deletions
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 63294aa54c0..cc68416d5fc 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -15,6 +15,7 @@ module Gitlab
autoload :IssueReferenceFilter, 'gitlab/markdown/issue_reference_filter'
autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter'
autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter'
+ autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter'
autoload :SanitizationFilter, 'gitlab/markdown/sanitization_filter'
autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter'
autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter'
@@ -64,7 +65,12 @@ module Gitlab
current_user: current_user,
only_path: options[:reference_only_path],
project: project,
- reference_class: html_options[:class]
+ reference_class: html_options[:class],
+
+ # RelativeLinkFilter
+ ref: @ref,
+ requested_path: @path,
+ project_wiki: @project_wiki
}
result = pipeline.call(text, context)
@@ -91,6 +97,7 @@ module Gitlab
[
Gitlab::Markdown::SanitizationFilter,
+ Gitlab::Markdown::RelativeLinkFilter,
Gitlab::Markdown::EmojiFilter,
Gitlab::Markdown::TableOfContentsFilter,
Gitlab::Markdown::AutolinkFilter,
diff --git a/lib/gitlab/markdown/relative_link_filter.rb b/lib/gitlab/markdown/relative_link_filter.rb
new file mode 100644
index 00000000000..deb302c88e1
--- /dev/null
+++ b/lib/gitlab/markdown/relative_link_filter.rb
@@ -0,0 +1,114 @@
+require 'html/pipeline/filter'
+require 'uri'
+
+module Gitlab
+ module Markdown
+ # HTML filter that "fixes" relative links to files in a repository.
+ #
+ # Context options:
+ # :commit
+ # :project
+ # :project_wiki
+ # :requested_path
+ # :ref
+ class RelativeLinkFilter < HTML::Pipeline::Filter
+
+ def call
+ if linkable_files?
+ doc.search('a').each do |el|
+ process_link_attr el.attribute('href')
+ end
+
+ doc.search('img').each do |el|
+ process_link_attr el.attribute('src')
+ end
+ end
+
+ doc
+ end
+
+ protected
+
+ def linkable_files?
+ context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty?
+ end
+
+ def process_link_attr(html_attr)
+ return if html_attr.blank?
+
+ uri = URI(html_attr.value)
+ if uri.relative? && uri.path.present?
+ html_attr.value = rebuild_relative_uri(uri).to_s
+ end
+ end
+
+ def rebuild_relative_uri(uri)
+ file_path = relative_file_path(uri.path)
+
+ uri.path = [
+ relative_url_root,
+ context[:project].path_with_namespace,
+ path_type(file_path),
+ ref || 'master', # assume that if no ref exists we can point to master
+ file_path
+ ].compact.join('/').squeeze('/').chomp('/')
+
+ uri
+ end
+
+ def relative_file_path(path)
+ nested_path = build_nested_path(path, context[:requested_path])
+ file_exists?(nested_path) ? nested_path : path
+ end
+
+ # Covering a special case, when the link is referencing file in the same
+ # directory.
+ # If we are at doc/api/README.md and the README.md contains relative
+ # links like [Users](users.md), this takes the request
+ # path(doc/api/README.md) and replaces the README.md with users.md so the
+ # path looks like doc/api/users.md.
+ # If we are at doc/api and the README.md shown in below the tree view
+ # this takes the request path(doc/api) and adds users.md so the path
+ # looks like doc/api/users.md
+ def build_nested_path(path, request_path)
+ return request_path if path.empty?
+ return path unless request_path
+
+ parts = request_path.split('/')
+ parts.pop if path_type(request_path) != 'tree'
+ parts.push(path).join('/')
+ end
+
+ def file_exists?(path)
+ return false if path.nil?
+ repository.blob_at(current_sha, path).present? ||
+ repository.tree(current_sha, path).entries.any?
+ end
+
+ # Check if the path is pointing to a directory(tree) or a file(blob)
+ # eg. doc/api is directory and doc/README.md is file.
+ def path_type(path)
+ return 'tree' if repository.tree(current_sha, path).entries.any?
+ return 'raw' if repository.blob_at(current_sha, path).try(:image?)
+ 'blob'
+ end
+
+ def current_sha
+ context[:commit].try(:id) ||
+ ref ? repository.commit(ref).try(:sha) : repository.head_commit.sha
+ end
+
+ def relative_url_root
+ Gitlab.config.gitlab.relative_url_root.presence || '/'
+ end
+
+ def ref
+ context[:ref]
+ end
+
+ def repository
+ context[:project].try(:repository)
+ end
+ end
+ end
+end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index bea66e6cdc1..15eb6effe08 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -36,10 +36,6 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
def postprocess(full_document)
- unless @template.instance_variable_get("@project_wiki") || @project.nil?
- full_document = h.create_relative_links(full_document)
- end
-
h.gfm_with_options(full_document, @options)
end
end