diff --git a/_config/routes.yml b/_config/routes.yml index 041a12f..b13af22 100644 --- a/_config/routes.yml +++ b/_config/routes.yml @@ -4,5 +4,5 @@ After: framework/routes#coreroutes --- Director: rules: - 'dev/docs//$Lang/$Action': 'DocumentationViewer' + 'dev/docs//$Action/$ID/$OtherID': 'DocumentationViewer' 'DocumentationOpenSearchController//$Action': 'DocumentationOpenSearchController' diff --git a/code/DocumentationManifest.php b/code/DocumentationManifest.php index a118dfd..a7d80e2 100644 --- a/code/DocumentationManifest.php +++ b/code/DocumentationManifest.php @@ -275,7 +275,40 @@ class DocumentationManifest { $this->handleFolder('', $this->entity->getPath(), 0); $finder->find($this->entity->getPath()); } + + // groupds + $grouped = array(); + + foreach($this->pages as $url => $page) { + if(!isset($grouped[$page['entitypath']])) { + $grouped[$page['entitypath']] = array(); + } + + $grouped[$page['entitypath']][$url] = $page; + } + + $this->pages = array(); + + foreach($grouped as $entity) { + uasort($entity, function($a, $b) { + // ensure parent directories are first + $a['filepath'] = str_replace('index.md', '', $a['filepath']); + $b['filepath'] = str_replace('index.md', '', $b['filepath']); + + if(strpos($b['filepath'], $a['filepath']) === 0) { + return -1; + } + + if ($a['filepath'] == $b['filepath']) { + return 0; + } + return ($a['filepath'] < $b['filepath']) ? -1 : 1; + }); + + $this->pages = array_merge($this->pages, $entity); + } + if ($cache) { $this->cache->save($this->pages, $this->cacheKey); } @@ -302,6 +335,7 @@ class DocumentationManifest { 'basename' => $basename, 'filepath' => $path, 'type' => 'DocumentationFolder', + 'entitypath' => $this->entity->getPath(), 'summary' => '' ); } @@ -336,6 +370,7 @@ class DocumentationManifest { $this->pages[$link] = array( 'title' => $page->getTitle(), 'filepath' => $path, + 'entitypath' => $this->entity->getPath(), 'basename' => $basename, 'type' => 'DocumentationPage', 'summary' => $page->getSummary() @@ -383,15 +418,17 @@ class DocumentationManifest { * Relies on the fact when the manifest was built, it was generated in * order. * - * @param string + * @param string $filepath + * @param string $entityBase * * @return ArrayData */ - public function getNextPage($filepath) { + public function getNextPage($filepath, $entityBase) { $grabNext = false; + $fallback = null; foreach($this->getPages() as $url => $page) { - if($grabNext) { + if($grabNext && strpos($page['filepath'], $entityBase) !== false) { return new ArrayData(array( 'Link' => $url, 'Title' => $page['title'] @@ -400,9 +437,19 @@ class DocumentationManifest { if($filepath == $page['filepath']) { $grabNext = true; + } else if(!$fallback && strpos($page['filepath'], $filepath) !== false) { + $fallback = new ArrayData(array( + 'Link' => $url, + 'Title' => $page['title'], + 'Fallback' => true + )); } } + if(!$grabNext) { + return $fallback; + } + return null; } @@ -412,11 +459,12 @@ class DocumentationManifest { * Relies on the fact when the manifest was built, it was generated in * order. * - * @param string + * @param string $filepath + * @param string $entityBase * * @return ArrayData */ - public function getPreviousPage($filepath) { + public function getPreviousPage($filepath, $entityPath) { $previousUrl = $previousPage = null; foreach($this->getPages() as $url => $page) { @@ -429,8 +477,10 @@ class DocumentationManifest { } } - $previousUrl = $url; - $previousPage = $page; + if(strpos($page['filepath'], $entityPath) !== false) { + $previousUrl = $url; + $previousPage = $page; + } } return null; @@ -578,15 +628,15 @@ class DocumentationManifest { $versions = array(); foreach($this->getEntities() as $entity) { - $versions[$entity->getVersion()] = $entity->getVersion(); + if($entity->getVersion()) { + $versions[$entity->getVersion()] = $entity->getVersion(); + } else { + $versions['0.0'] = _t('DocumentationManifest.MASTER', 'Master'); + } } - $uniqueVersions = array_unique( - ArrayLib::flatten(array_values($versions)) - ); + asort($versions); - asort($uniqueVersions); - - return array_combine($uniqueVersions, $uniqueVersions); + return $versions; } } diff --git a/css/layout.css b/css/layout.css index 1d79a6c..17b9e91 100644 --- a/css/layout.css +++ b/css/layout.css @@ -351,7 +351,7 @@ html { .hint, .note { border: 1px dotted #a5b5b0; - padding: 13px 10px 0px 60px; + padding: 14px 10px 14px 60px; clear: both; margin: 9px 0 18px; background: #f9fafa url(../../docsviewer/images/lightbulb.png) no-repeat 21px 14px; diff --git a/tests/DocumentationManifestTests.php b/tests/DocumentationManifestTests.php index 1747d14..3ba3f57 100644 --- a/tests/DocumentationManifestTests.php +++ b/tests/DocumentationManifestTests.php @@ -45,6 +45,11 @@ class DocumentationManifestTests extends SapphireTest { 'Title' => 'Doc Test', 'Key' => 'testdocs', 'Version' => '3.0' + ), + array( + 'Path' => DOCSVIEWER_PATH . "/tests/docs-manifest/", + 'Title' => 'Manifest', + 'Key' => 'manifest' ) ) ); @@ -69,33 +74,79 @@ class DocumentationManifestTests extends SapphireTest { 'de/testdocs/2.3/test/', 'en/testdocs/2.3/', 'en/testdocs/2.3/sort/', - 'en/testdocs/2.3/subfolder/', - 'en/testdocs/2.3/test/', 'en/testdocs/2.3/sort/basic/', - 'en/testdocs/2.3/sort/some-page/', 'en/testdocs/2.3/sort/intermediate/', - 'en/testdocs/2.3/sort/another-page/', 'en/testdocs/2.3/sort/advanced/', + 'en/testdocs/2.3/sort/some-page/', + 'en/testdocs/2.3/sort/another-page/', + 'en/testdocs/2.3/subfolder/', 'en/testdocs/2.3/subfolder/subpage/', 'en/testdocs/2.3/subfolder/subsubfolder/', 'en/testdocs/2.3/subfolder/subsubfolder/subsubpage/', + 'en/testdocs/2.3/test/', 'en/testdocs/', 'en/testdocs/test/', 'en/testdocs/3.0/', 'en/testdocs/3.0/changelog/', 'en/testdocs/3.0/tutorials/', - 'en/testdocs/3.0/empty/' + 'en/testdocs/3.0/empty/', + 'en/manifest/', + 'en/manifest/guide/', + 'en/manifest/guide/test/', + 'en/manifest/second-guide/', + 'en/manifest/second-guide/afile/' ); $this->assertEquals($match, array_keys($this->manifest->getPages())); } public function testGetNextPage() { - $this->markTestIncomplete(); + // get next page at the end of one subfolder goes back up to the top + // most directory + $this->assertStringEndsWith('2.3/test/', $this->manifest->getNextPage( + DOCSVIEWER_PATH . '/tests/docs/en/subfolder/subsubfolder/subsubpage.md', + DOCSVIEWER_PATH . '/tests/docs/en/' + )->Link); + + // after sorting, 2 is shown. + $this->assertContains('/intermediate/', $this->manifest->getNextPage( + DOCSVIEWER_PATH . '/tests/docs/en/sort/01-basic.md', + DOCSVIEWER_PATH . '/tests/docs/en/' + )->Link); + + + // next gets the following URL + $this->assertContains('/test/', $this->manifest->getNextPage( + DOCSVIEWER_PATH . '/tests/docs-v2.4/en/index.md', + DOCSVIEWER_PATH . '/tests/docs-v2.4/en/' + )->Link); + + + // last folder in a entity does not leak + $this->assertNull($this->manifest->getNextPage( + DOCSVIEWER_PATH . '/tests/docs/en/test.md', + DOCSVIEWER_PATH . '/tests/docs/en/' + )); } public function testGetPreviousPage() { - $this->markTestIncomplete(); + // goes right into subfolders + $this->assertContains('subfolder/subsubfolder/subsubpage', $this->manifest->getPreviousPage( + DOCSVIEWER_PATH . '/tests/docs/en/test.md', + DOCSVIEWER_PATH . '/tests/docs/en/' + )->Link); + + // does not leak between entities + $this->assertNull($this->manifest->getPreviousPage( + DOCSVIEWER_PATH . '/tests/docs/en/index.md', + DOCSVIEWER_PATH . '/tests/docs/en/' + )); + + // does not leak between entities + $this->assertNull($this->manifest->getPreviousPage( + DOCSVIEWER_PATH . ' /tests/docs/en/index.md', + DOCSVIEWER_PATH . '/tests/docs/en/' + )); } public function testGetPage() { @@ -131,8 +182,9 @@ class DocumentationManifestTests extends SapphireTest { $expected = array( '2.3' => '2.3', '2.4' => '2.4', - '3.0' => '3.0' - ); + '3.0' => '3.0', + '0.0' => 'Master' + ); $this->assertEquals($expected, $this->manifest->getAllVersions()); } diff --git a/tests/docs-manifest/en/guide/index.md b/tests/docs-manifest/en/guide/index.md new file mode 100644 index 0000000..24aa617 --- /dev/null +++ b/tests/docs-manifest/en/guide/index.md @@ -0,0 +1 @@ +# File \ No newline at end of file diff --git a/tests/docs-manifest/en/guide/test.md b/tests/docs-manifest/en/guide/test.md new file mode 100644 index 0000000..00bcb6e --- /dev/null +++ b/tests/docs-manifest/en/guide/test.md @@ -0,0 +1 @@ +# test \ No newline at end of file diff --git a/tests/docs-manifest/en/index.md b/tests/docs-manifest/en/index.md new file mode 100644 index 0000000..21e60f8 --- /dev/null +++ b/tests/docs-manifest/en/index.md @@ -0,0 +1 @@ +# Test \ No newline at end of file diff --git a/tests/docs-manifest/en/second-guide/afile.md b/tests/docs-manifest/en/second-guide/afile.md new file mode 100644 index 0000000..24aa617 --- /dev/null +++ b/tests/docs-manifest/en/second-guide/afile.md @@ -0,0 +1 @@ +# File \ No newline at end of file diff --git a/tests/docs-manifest/en/second-guide/index.md b/tests/docs-manifest/en/second-guide/index.md new file mode 100644 index 0000000..4cf9b72 --- /dev/null +++ b/tests/docs-manifest/en/second-guide/index.md @@ -0,0 +1 @@ +# index \ No newline at end of file diff --git a/tests/docs/en/index.md b/tests/docs/en/index.md index 5f74132..4f1402e 100755 --- a/tests/docs/en/index.md +++ b/tests/docs/en/index.md @@ -2,4 +2,7 @@ index -1.0 \ No newline at end of file +1.0 + +[link: subfolder index](subfolder) + diff --git a/tests/docs/en/sort/1-basic.md b/tests/docs/en/sort/01-basic.md similarity index 100% rename from tests/docs/en/sort/1-basic.md rename to tests/docs/en/sort/01-basic.md diff --git a/tests/docs/en/sort/2-intermediate.md b/tests/docs/en/sort/02-intermediate.md similarity index 100% rename from tests/docs/en/sort/2-intermediate.md rename to tests/docs/en/sort/02-intermediate.md diff --git a/tests/docs/en/sort/3-advanced.md b/tests/docs/en/sort/03-advanced.md similarity index 100% rename from tests/docs/en/sort/3-advanced.md rename to tests/docs/en/sort/03-advanced.md