diff options
author | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2015-05-13 14:26:39 +0300 |
---|---|---|
committer | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2015-05-13 14:26:39 +0300 |
commit | 63403019d286ae5dc7ff2481f8a948da96057489 (patch) | |
tree | 711eafd76030433ef6ba6dfcb1887c1902b095a9 /lib | |
parent | f32a045ef41688859732abfcdc2a2030387be78f (diff) | |
parent | 740716afd16e6487c965caf9c2f63e99fc78c076 (diff) | |
download | gitlab-ce-63403019d286ae5dc7ff2481f8a948da96057489.tar.gz |
Merge branch 'master' of github.com:gitlabhq/gitlabhq
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/markdown.rb | 9 | ||||
-rw-r--r-- | lib/gitlab/markdown/relative_link_filter.rb | 114 | ||||
-rw-r--r-- | lib/redcarpet/render/gitlab_html.rb | 4 |
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 |