Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kazuhiko Shiozaki
gitlab-ce
Commits
f7adac87
Commit
f7adac87
authored
May 11, 2015
by
Jakub Jirutka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extract handling of relative file links to RelativeLinkFilter
parent
6fdc51f8
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
126 additions
and
145 deletions
+126
-145
app/helpers/gitlab_markdown_helper.rb
app/helpers/gitlab_markdown_helper.rb
+0
-140
lib/gitlab/markdown.rb
lib/gitlab/markdown.rb
+9
-1
lib/gitlab/markdown/relative_link_filter.rb
lib/gitlab/markdown/relative_link_filter.rb
+117
-0
lib/redcarpet/render/gitlab_html.rb
lib/redcarpet/render/gitlab_html.rb
+0
-4
No files found.
app/helpers/gitlab_markdown_helper.rb
View file @
f7adac87
...
@@ -72,146 +72,6 @@ module GitlabMarkdownHelper
...
@@ -72,146 +72,6 @@ module GitlabMarkdownHelper
end
end
end
end
# TODO (rspeicher): This should be its own filter
def
create_relative_links
(
text
)
paths
=
extract_paths
(
text
)
paths
.
uniq
.
each
do
|
file_path
|
# If project does not have repository
# its nothing to rebuild
#
# TODO: pass project variable to markdown helper instead of using
# instance variable. Right now it generates invalid path for pages out
# of project scope. Example: search results where can be rendered markdown
# from different projects
if
@repository
&&
@repository
.
exists?
&&
!
@repository
.
empty?
new_path
=
rebuild_path
(
file_path
)
# Finds quoted path so we don't replace other mentions of the string
# eg. "doc/api" will be replaced and "/home/doc/api/text" won't
text
.
gsub!
(
"
\"
#{
file_path
}
\"
"
,
"
\"
/
#{
new_path
}
\"
"
)
end
end
text
end
def
extract_paths
(
text
)
links
=
substitute_links
(
text
)
image_links
=
substitute_image_links
(
text
)
links
+
image_links
end
def
substitute_links
(
text
)
links
=
text
.
scan
(
/<a href=\"([^"]*)\">/
)
relative_links
=
links
.
flatten
.
reject
{
|
link
|
link_to_ignore?
link
}
relative_links
end
def
substitute_image_links
(
text
)
links
=
text
.
scan
(
/<img src=\"([^"]*)\"/
)
relative_links
=
links
.
flatten
.
reject
{
|
link
|
link_to_ignore?
link
}
relative_links
end
def
link_to_ignore?
(
link
)
if
link
=~
/\A\#\w+/
# ignore anchors like <a href="#my-header">
true
else
ignored_protocols
.
map
{
|
protocol
|
link
.
include?
(
protocol
)
}.
any?
end
end
def
ignored_protocols
[
"http://"
,
"https://"
,
"ftp://"
,
"mailto:"
,
"smb://"
]
end
def
rebuild_path
(
file_path
)
file_path
=
file_path
.
dup
file_path
.
gsub!
(
/(#.*)/
,
""
)
id
=
$1
||
""
file_path
=
relative_file_path
(
file_path
)
file_path
=
sanitize_slashes
(
file_path
)
[
Gitlab
.
config
.
gitlab
.
relative_url_root
,
@project
.
path_with_namespace
,
path_with_ref
(
file_path
),
file_path
].
compact
.
join
(
"/"
).
gsub
(
/\A\/*|\/*\z/
,
''
)
+
id
end
def
sanitize_slashes
(
path
)
path
[
0
]
=
""
if
path
.
start_with?
(
"/"
)
path
.
chop
if
path
.
end_with?
(
"/"
)
path
end
def
relative_file_path
(
path
)
requested_path
=
@path
nested_path
=
build_nested_path
(
path
,
requested_path
)
return
nested_path
if
file_exists?
(
nested_path
)
path
end
# Covering a special case, when the link is referencing file in the same directory eg:
# 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
==
""
return
path
unless
request_path
if
local_path
(
request_path
)
==
"tree"
base
=
request_path
.
split
(
"/"
).
push
(
path
)
base
.
join
(
"/"
)
else
base
=
request_path
.
split
(
"/"
)
base
.
pop
base
.
push
(
path
).
join
(
"/"
)
end
end
# Checks if the path exists in the repo
# eg. checks if doc/README.md exists, if not then link to blob
def
path_with_ref
(
path
)
if
file_exists?
(
path
)
"
#{
local_path
(
path
)
}
/
#{
correct_ref
}
"
else
"blob/
#{
correct_ref
}
"
end
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
local_path
(
path
)
return
"tree"
if
@repository
.
tree
(
current_sha
,
path
).
entries
.
any?
return
"raw"
if
@repository
.
blob_at
(
current_sha
,
path
).
image?
"blob"
end
def
current_sha
if
@commit
@commit
.
id
elsif
@repository
&&
!
@repository
.
empty?
if
@ref
@repository
.
commit
(
@ref
).
try
(
:sha
)
else
@repository
.
head_commit
.
sha
end
end
end
# We will assume that if no ref exists we can point to master
def
correct_ref
@ref
?
@ref
:
"master"
end
private
private
# Return +text+, truncated to +max_chars+ characters, excluding any HTML
# Return +text+, truncated to +max_chars+ characters, excluding any HTML
...
...
lib/gitlab/markdown.rb
View file @
f7adac87
...
@@ -15,6 +15,7 @@ module Gitlab
...
@@ -15,6 +15,7 @@ module Gitlab
autoload
:IssueReferenceFilter
,
'gitlab/markdown/issue_reference_filter'
autoload
:IssueReferenceFilter
,
'gitlab/markdown/issue_reference_filter'
autoload
:LabelReferenceFilter
,
'gitlab/markdown/label_reference_filter'
autoload
:LabelReferenceFilter
,
'gitlab/markdown/label_reference_filter'
autoload
:MergeRequestReferenceFilter
,
'gitlab/markdown/merge_request_reference_filter'
autoload
:MergeRequestReferenceFilter
,
'gitlab/markdown/merge_request_reference_filter'
autoload
:RelativeLinkFilter
,
'gitlab/markdown/relative_link_filter'
autoload
:SanitizationFilter
,
'gitlab/markdown/sanitization_filter'
autoload
:SanitizationFilter
,
'gitlab/markdown/sanitization_filter'
autoload
:SnippetReferenceFilter
,
'gitlab/markdown/snippet_reference_filter'
autoload
:SnippetReferenceFilter
,
'gitlab/markdown/snippet_reference_filter'
autoload
:TableOfContentsFilter
,
'gitlab/markdown/table_of_contents_filter'
autoload
:TableOfContentsFilter
,
'gitlab/markdown/table_of_contents_filter'
...
@@ -64,7 +65,12 @@ module Gitlab
...
@@ -64,7 +65,12 @@ module Gitlab
current_user:
current_user
,
current_user:
current_user
,
only_path:
options
[
:reference_only_path
],
only_path:
options
[
:reference_only_path
],
project:
project
,
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
)
result
=
pipeline
.
call
(
text
,
context
)
...
@@ -91,6 +97,8 @@ module Gitlab
...
@@ -91,6 +97,8 @@ module Gitlab
[
[
Gitlab
::
Markdown
::
SanitizationFilter
,
Gitlab
::
Markdown
::
SanitizationFilter
,
Gitlab
::
Markdown
::
RelativeLinkFilter
,
Gitlab
::
Markdown
::
EmojiFilter
,
Gitlab
::
Markdown
::
EmojiFilter
,
Gitlab
::
Markdown
::
TableOfContentsFilter
,
Gitlab
::
Markdown
::
TableOfContentsFilter
,
Gitlab
::
Markdown
::
AutolinkFilter
,
Gitlab
::
Markdown
::
AutolinkFilter
,
...
...
lib/gitlab/markdown/relative_link_filter.rb
0 → 100644
View file @
f7adac87
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
!
project_wiki
&&
repository
.
try
(
:exists?
)
&&
!
repository
.
empty?
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
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
,
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
,
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
if
commit
commit
.
id
elsif
ref
repository
.
commit
(
ref
).
try
(
:sha
)
else
repository
.
head_commit
.
sha
end
end
def
relative_url_root
Gitlab
.
config
.
gitlab
.
relative_url_root
.
presence
||
'/'
end
[
:commit
,
:project
,
:project_wiki
,
:requested_path
,
:ref
].
each
do
|
name
|
define_method
(
name
)
do
context
[
name
]
end
end
def
repository
return
if
project
.
nil?
project
.
repository
end
end
end
end
lib/redcarpet/render/gitlab_html.rb
View file @
f7adac87
...
@@ -36,10 +36,6 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
...
@@ -36,10 +36,6 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
end
def
postprocess
(
full_document
)
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
)
h
.
gfm_with_options
(
full_document
,
@options
)
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment