diff --git a/docs/user-guide/configuration.md b/docs/user-guide/configuration.md index 92efebfd..ddb3eb94 100644 --- a/docs/user-guide/configuration.md +++ b/docs/user-guide/configuration.md @@ -75,6 +75,18 @@ follows. (Note the `src` path and `default` branch...) edit_uri: src/default/docs/ ``` +The `edit_uri` also supports query ('?') and fragment ('#') characters. For +reposotiry hosts that use a query or a fragment to access the files, the +`edit_uri` would be as follows. (Note the `?` and `#` in the uri...) + +```yaml +# Query string example +edit_uri: '?query=root/path/docs/' + +# Hash fragment example +edit_uri: '#root/path/docs/' +``` + For other repository hosts, `edit_uri` works the same way. Simply specify the relative path to the docs directory. diff --git a/mkdocs/nav.py b/mkdocs/nav.py index fb092e66..a0fa030c 100644 --- a/mkdocs/nav.py +++ b/mkdocs/nav.py @@ -205,15 +205,19 @@ class Page(object): def set_edit_url(self, repo_url, edit_uri): if not repo_url.endswith('/'): - repo_url += '/' + # Skip when using query or fragment in edit_uri + if not edit_uri.startswith('?') and not edit_uri.startswith('#'): + repo_url += '/' if not edit_uri: self.edit_url = repo_url else: + # Normalize URL from Windows path '\\' -> '/' + input_path_url = self.input_path.replace('\\', '/') if not edit_uri.endswith('/'): edit_uri += '/' self.edit_url = utils.urljoin( - repo_url + edit_uri, - self.input_path) + repo_url, + edit_uri + input_path_url) class Header(object): diff --git a/mkdocs/tests/nav_tests.py b/mkdocs/tests/nav_tests.py index 282c1c37..7cab5e34 100644 --- a/mkdocs/tests/nav_tests.py +++ b/mkdocs/tests/nav_tests.py @@ -610,3 +610,149 @@ class TestLegacyPagesConfig(unittest.TestCase): self.assertEqual(str(site_navigation).strip(), expected) self.assertEqual(len(site_navigation.nav_items), 3) self.assertEqual(len(site_navigation.pages), 6) + + def test_edit_uri(self): + """ + Ensure that set_edit_url creates well formed URLs for edit_uri + """ + + pages = [ + 'index.md', + 'internal.md', + 'sub/internal.md', + 'sub1/sub2/internal.md', + ] + + # Basic test + repo_url = 'http://example.com/' + edit_uri = 'edit/master/docs/' + + site_navigation = nav.SiteNavigation(pages) + + expected_results = ( + repo_url + edit_uri + pages[0], + repo_url + edit_uri + pages[1], + repo_url + edit_uri + pages[2], + repo_url + edit_uri + pages[3], + ) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + # Ensure the '/' is added to the repo_url and edit_uri + repo_url = 'http://example.com' + edit_uri = 'edit/master/docs' + + site_navigation = nav.SiteNavigation(pages) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + # Ensure query strings are supported + repo_url = 'http://example.com' + edit_uri = '?query=edit/master/docs/' + + site_navigation = nav.SiteNavigation(pages) + + expected_results = ( + repo_url + edit_uri + pages[0], + repo_url + edit_uri + pages[1], + repo_url + edit_uri + pages[2], + repo_url + edit_uri + pages[3], + ) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + # Ensure fragment strings are supported + repo_url = 'http://example.com' + edit_uri = '#fragment/edit/master/docs/' + + site_navigation = nav.SiteNavigation(pages) + + expected_results = ( + repo_url + edit_uri + pages[0], + repo_url + edit_uri + pages[1], + repo_url + edit_uri + pages[2], + repo_url + edit_uri + pages[3], + ) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + def test_edit_uri_windows(self): + """ + Ensure that set_edit_url creates well formed URLs for edit_uri with a windows path + """ + + pages = [ + 'index.md', + 'internal.md', + 'sub\\internal.md', + 'sub1\\sub2\\internal.md', + ] + + # Basic test + repo_url = 'http://example.com/' + edit_uri = 'edit/master/docs/' + + site_navigation = nav.SiteNavigation(pages) + + expected_results = ( + repo_url + edit_uri + pages[0], + repo_url + edit_uri + pages[1], + repo_url + edit_uri + pages[2].replace('\\', '/'), + repo_url + edit_uri + pages[3].replace('\\', '/'), + ) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + # Ensure the '/' is added to the repo_url and edit_uri + repo_url = 'http://example.com' + edit_uri = 'edit/master/docs' + + site_navigation = nav.SiteNavigation(pages) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + # Ensure query strings are supported + repo_url = 'http://example.com' + edit_uri = '?query=edit/master/docs/' + + site_navigation = nav.SiteNavigation(pages) + + expected_results = ( + repo_url + edit_uri + pages[0], + repo_url + edit_uri + pages[1], + repo_url + edit_uri + pages[2].replace('\\', '/'), + repo_url + edit_uri + pages[3].replace('\\', '/'), + ) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx]) + + # Ensure fragment strings are supported + repo_url = 'http://example.com' + edit_uri = '#fragment/edit/master/docs/' + + site_navigation = nav.SiteNavigation(pages) + + expected_results = ( + repo_url + edit_uri + pages[0], + repo_url + edit_uri + pages[1], + repo_url + edit_uri + pages[2].replace('\\', '/'), + repo_url + edit_uri + pages[3].replace('\\', '/'), + ) + + for idx, page in enumerate(site_navigation.walk_pages()): + page.set_edit_url(repo_url, edit_uri) + self.assertEqual(page.edit_url, expected_results[idx])