Repository: mkdocs/mkdocs

Issue:
Relative links in pages below the top-level document folder point to the wrong path
Relative image links in pages below the top-level document folder seem to point to the wrong path.
## Reproduction

I've created a minimal reproduction case:
https://github.com/jdhoek/mkdocs-test-relative-image-links

The reproduction case contains this file structure:

```
├── docs
│   ├── index.md
│   ├── subdir
│   │   ├── sub.md
│   │   └── sub.png
│   └── toplevel.png
└── mkdocs.yml
```

`mkdocs serve` and `mkdocs build` correctly process the Markdown files in the top-level folder `docs_dir`, but with the Markdown file in the sub-folder the relative image links are broken.

![mkdocs-relative-image-links](https://cloud.githubusercontent.com/assets/683699/5486734/3fd98a18-86aa-11e4-9243-059b656efa19.png)



Discussion:
Probably same as #77 but this is more helpful.

I wasn't sure if #77 was the exact same issue. Thanks for referencing it.

This is a great report, thanks very much.

Things gets a bit confusing as, I think, we have links in three different scenarios.
- Links to markdown (as far as I'm aware, no known issues)
- Links to static assets like images (this issue)
- Either of the above on a "static page" like the `404.html` which could be returned under many paths. (this is probably #77).

The first two vary because we move the location of markdown files (`my/document.md` becomes `my/document/index.html` and is thus one level deeper). So, these issues are probably subtly different but I expect a fix will need to take all the above into account.

@jdhoek Just to check, did you test this against the latest release or via git master? There was some fairly recent fixes for images, but I can't remember if it made the last release or not :)

... I just confirmed, it is still an issue with the latest dev version.

I can't see an obvious reason, but the broken image path is coming out as `../../sub.png` when it should be `../sub.png`.

Gah, I see the issue with images. It comes down to my miss-understanding of the url rewriting when I added support for them. it is actually a _coincidence_ that any of these work. :flushed: 

Clearly the tests I added for this are completely bogus. I'll look into a real fix.

Using `create_media_urls` here is completely wrong. https://github.com/tomchristie/mkdocs/blob/aaf344630f4732ae58d1da28b25d0c02bd8d56b9/mkdocs/relative_path_ext.py#L59

@d0ugal 
My apologies, I should have mentioned the version. I am using the latest stable release from PyPI; v0.11.1.


Resolving patch:
diff --git a/mkdocs/relative_path_ext.py b/mkdocs/relative_path_ext.py
--- a/mkdocs/relative_path_ext.py
+++ b/mkdocs/relative_path_ext.py
@@ -56,7 +56,7 @@ def path_to_url(url, nav):
         return url
 
     if nav and not utils.is_markdown_file(path):
-        path = utils.create_media_urls(nav, [path])[0]
+        path = utils.create_relative_media_url(nav, path)
     elif nav:
         # If the site navigation has been provided, then validate
         # the internal hyperlink, making sure the target actually exists.
diff --git a/mkdocs/utils.py b/mkdocs/utils.py
--- a/mkdocs/utils.py
+++ b/mkdocs/utils.py
@@ -166,3 +166,41 @@ def create_media_urls(nav, url_list):
             relative_url = '%s/%s' % (nav.url_context.make_relative('/'), url)
             final_urls.append(relative_url)
     return final_urls
+
+
+def create_relative_media_url(nav, url):
+    """
+    For a current page, create a relative url based on the given URL.
+
+    On index.md (which becomes /index.html):
+        image.png -> ./image.png
+        /image.png -> ./image.png
+
+    on sub/page.md (which becomes /sub/page/index.html):
+        image.png -> ../image.png
+        /image.png -> ../../image.png
+
+    """
+
+    # Allow links to fully qualified URL's
+    parsed = urlparse(url)
+    if parsed.netloc:
+        return url
+
+    # If the URL we are looking at starts with a /, then it should be
+    # considered as absolute and will be 'relative' to the root.
+    if url.startswith('/'):
+        base = '/'
+        url = url[1:]
+    else:
+        base = nav.url_context.base_path
+
+    relative_url = '%s/%s' % (nav.url_context.make_relative(base), url)
+
+    # TODO: Fix this, this is a hack. Relative urls are not being calculated
+    # correctly for images in the same directory as the markdown. I think this
+    # is due to us moving it into a directory with index.html, but I'm not sure
+    if nav.url_context.base_path is not '/' and relative_url.startswith("./"):
+        relative_url = ".%s" % relative_url
+
+    return relative_url


Test patch:
diff --git a/mkdocs/test.py b/mkdocs/test.py
--- a/mkdocs/test.py
+++ b/mkdocs/test.py
@@ -518,6 +518,7 @@ def test_convert_internal_link_with_anchor(self):
         self.assertEqual(html.strip(), expected.strip())
 
     def test_convert_internal_media(self):
+        """Test relative image URL's are the same for different base_urls"""
         pages = [
             ('index.md',),
             ('internal.md',),
@@ -527,15 +528,40 @@ def test_convert_internal_media(self):
         site_navigation = nav.SiteNavigation(pages)
 
         expected_results = (
-            '<p><img alt="The initial MkDocs layout" src="./img/initial-layout.png" /></p>\n',
-            '<p><img alt="The initial MkDocs layout" src="../img/initial-layout.png" /></p>\n',
-            '<p><img alt="The initial MkDocs layout" src="../../img/initial-layout.png" /></p>\n',
+            './img/initial-layout.png',
+            '../img/initial-layout.png',
+            '../img/initial-layout.png',
         )
 
+        template = '<p><img alt="The initial MkDocs layout" src="%s" /></p>\n'
+
         for (page, expected) in zip(site_navigation.walk_pages(), expected_results):
             md_text = '![The initial MkDocs layout](img/initial-layout.png)'
             html, _, _ = build.convert_markdown(md_text, site_navigation=site_navigation)
-            self.assertEqual(html, expected)
+            self.assertEqual(html, template % expected)
+
+    def test_convert_internal_asbolute_media(self):
+        """Test absolute image URL's are correct for different base_urls"""
+        pages = [
+            ('index.md',),
+            ('internal.md',),
+            ('sub/internal.md')
+        ]
+
+        site_navigation = nav.SiteNavigation(pages)
+
+        expected_results = (
+            './img/initial-layout.png',
+            '../img/initial-layout.png',
+            '../../img/initial-layout.png',
+        )
+
+        template = '<p><img alt="The initial MkDocs layout" src="%s" /></p>\n'
+
+        for (page, expected) in zip(site_navigation.walk_pages(), expected_results):
+            md_text = '![The initial MkDocs layout](/img/initial-layout.png)'
+            html, _, _ = build.convert_markdown(md_text, site_navigation=site_navigation)
+            self.assertEqual(html, template % expected)
 
     def test_dont_convert_code_block_urls(self):
         pages = [