mirror of
https://github.com/silverstripe/silverstripe-docsviewer
synced 2024-10-22 11:05:56 +02:00
ENHANCEMENT: use urls in the format module/lang/version rather than version first. Tweaks to the parser to prevent infinite loops
This commit is contained in:
parent
24f1b13233
commit
fc8ab96c51
@ -16,6 +16,8 @@ Reads markdown documentation files from the /docs/ folder in . To read documenta
|
||||
For more documentation on how to use the module please read /docs/Writing-Documentation.md
|
||||
(or via this in /dev/docs/sapphiredocs/Writing-Documentation in your webbrowser)
|
||||
|
||||
**Note** This module assumes you are using numeric values for your versions.
|
||||
|
||||
## Syntax Highlighting ##
|
||||
|
||||
The custom Markdown parser can render custom prefixes for code blocks,
|
||||
@ -58,4 +60,4 @@ To include the syntax highlighter source, add the following to your `Documentati
|
||||
Requirements::css('sapphiredocs/thirdparty/syntaxhighlighter/styles/shThemeRDark.css');
|
||||
|
||||
You can overload the `DocumentationViewer` class and add a custom route through `Director::addRule()`
|
||||
if you prefer not to modify the module file.>>>>>>> .r115400
|
||||
if you prefer not to modify the module file.
|
||||
|
@ -238,9 +238,9 @@ class DocumentationEntity extends ViewableData {
|
||||
return Controller::join_links(
|
||||
Director::absoluteBaseURL(),
|
||||
DocumentationViewer::get_link_base(),
|
||||
$version,
|
||||
$this->moduleFolder,
|
||||
$lang,
|
||||
$this->moduleFolder
|
||||
$version
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -34,10 +34,11 @@ class DocumentationParser {
|
||||
if(!$page || (!$page instanceof DocumentationPage)) return false;
|
||||
|
||||
$md = $page->getMarkdown();
|
||||
|
||||
|
||||
// Pre-processing
|
||||
$md = self::rewrite_image_links($md, $page);
|
||||
$md = self::rewrite_relative_links($md, $page, $baselink);
|
||||
|
||||
$md = self::rewrite_api_links($md, $page);
|
||||
$md = self::rewrite_heading_anchors($md, $page);
|
||||
$md = self::rewrite_code_blocks($md, $page);
|
||||
@ -103,6 +104,7 @@ class DocumentationParser {
|
||||
|
||||
// Don't process absolute links (based on protocol detection)
|
||||
$urlParts = parse_url($url);
|
||||
|
||||
if($urlParts && isset($urlParts['scheme'])) continue;
|
||||
|
||||
// Rewrite URL (relative or absolute)
|
||||
@ -246,6 +248,7 @@ class DocumentationParser {
|
||||
* @return String Markdown
|
||||
*/
|
||||
static function rewrite_relative_links($md, $page, $baselink) {
|
||||
|
||||
$re = '/
|
||||
([^\!]?) # exclude image format
|
||||
\[
|
||||
@ -262,6 +265,7 @@ class DocumentationParser {
|
||||
if($relativePath == '.') $relativePath = '';
|
||||
|
||||
if($matches) {
|
||||
|
||||
foreach($matches[0] as $i => $match) {
|
||||
$title = $matches[2][$i];
|
||||
$url = $matches[3][$i];
|
||||
@ -272,12 +276,12 @@ class DocumentationParser {
|
||||
// Don't process absolute links (based on protocol detection)
|
||||
$urlParts = parse_url($url);
|
||||
if($urlParts && isset($urlParts['scheme'])) continue;
|
||||
|
||||
|
||||
// Rewrite URL (relative or absolute)
|
||||
if(preg_match('/^\//', $url)) {
|
||||
$relativeUrl = $baselink . $url;
|
||||
$relativeUrl = Controller::join_links($baselink, $url);
|
||||
} else {
|
||||
$relativeUrl = $baselink . '/' . $relativePath . '/' . $url;
|
||||
$relativeUrl = Controller::join_links($baselink, $relativePath, $url);
|
||||
}
|
||||
|
||||
// Resolve relative paths
|
||||
|
@ -232,13 +232,14 @@ class DocumentationService {
|
||||
* @return DocumentationEntity $module the registered module
|
||||
*/
|
||||
public static function is_registered_module($module, $version = false, $lang = false) {
|
||||
|
||||
$check = ($module instanceof DocumentationEntity) ? $module->getModuleFolder() : (string) $module;
|
||||
|
||||
|
||||
if(isset(self::$registered_modules[$check])) {
|
||||
$module = self::$registered_modules[$check];
|
||||
if($lang && !$module->hasLanguage($lang)) return false;
|
||||
if($version && !$module->hasVersion($version)) return false;
|
||||
|
||||
if(($lang && !$module->hasLanguage($lang)) || ($version && !$module->hasVersion($version))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $module;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class DocumentationViewer extends Controller {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $version = "current";
|
||||
public $version = "";
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -128,7 +128,6 @@ class DocumentationViewer extends Controller {
|
||||
$thirdParam = $request->shift();
|
||||
|
||||
$this->Remaining = $request->shift(10);
|
||||
|
||||
DocumentationService::load_automatic_registration();
|
||||
|
||||
if(isset($firstParam)) {
|
||||
@ -146,33 +145,34 @@ class DocumentationViewer extends Controller {
|
||||
return $this->response;
|
||||
|
||||
}
|
||||
else if(is_numeric($firstParam) || $firstParam == "current") {
|
||||
// its a version number first in the form 2.4/en/sapphire
|
||||
$this->version = $firstParam;
|
||||
$this->lang = $secondParam;
|
||||
$this->module = $thirdParam;
|
||||
|
||||
$this->module = $firstParam;
|
||||
$this->lang = $secondParam;
|
||||
|
||||
if(isset($thirdParam) && (is_numeric($thirdParam))) {
|
||||
$this->version = $thirdParam;
|
||||
}
|
||||
else {
|
||||
// we have a language first in the form /en/sapphire
|
||||
// current version so store one area para
|
||||
array_unshift($this->Remaining, $thirdParam);
|
||||
|
||||
$this->lang = $firstParam;
|
||||
$this->module = $secondParam;
|
||||
|
||||
$this->version = "";
|
||||
}
|
||||
}
|
||||
|
||||
// 'current' version mapping
|
||||
$module = DocumentationService::is_registered_module($this->module, null, $this->getLang());
|
||||
|
||||
if($module && $this->getVersion()) {
|
||||
|
||||
if($module) {
|
||||
$current = $module->getCurrentVersion();
|
||||
|
||||
|
||||
$version = $this->getVersion();
|
||||
|
||||
if($version == 'current') {
|
||||
if(!$version || $version == '') {
|
||||
$this->version = $current;
|
||||
} else if($current == $version) {
|
||||
$this->version = 'current';
|
||||
$this->version = '';
|
||||
|
||||
$link = $this->Link($this->Remaining);
|
||||
$this->response = new SS_HTTPResponse();
|
||||
|
||||
@ -180,8 +180,7 @@ class DocumentationViewer extends Controller {
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return parent::handleRequest($request);
|
||||
}
|
||||
@ -216,7 +215,8 @@ class DocumentationViewer extends Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version
|
||||
* Returns the current version. If no version is set then it is the current
|
||||
* set version so need to pull that from the module
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@ -369,9 +369,9 @@ class DocumentationViewer extends Controller {
|
||||
*/
|
||||
function getPage() {
|
||||
$module = $this->getModule();
|
||||
|
||||
if(!$module) return false;
|
||||
|
||||
if(!$module) return false;
|
||||
|
||||
$absFilepath = DocumentationService::find_page($module, $this->Remaining);
|
||||
|
||||
if($absFilepath) {
|
||||
@ -399,7 +399,7 @@ class DocumentationViewer extends Controller {
|
||||
function getModulePages() {
|
||||
if($module = $this->getModule()) {
|
||||
$pages = DocumentationService::get_pages_from_folder($module, null, false);
|
||||
|
||||
|
||||
if($pages) {
|
||||
foreach($pages as $page) {
|
||||
if(strtolower($page->Title) == "index") {
|
||||
@ -479,7 +479,7 @@ class DocumentationViewer extends Controller {
|
||||
if($page = $this->getPage()) {
|
||||
|
||||
// Remove last portion of path (filename), we want a link to the folder base
|
||||
$html = DocumentationParser::parse($page, $this->Link(array_slice($this->Remaining, -1, -1)));
|
||||
$html = DocumentationParser::parse($page, $this->Link(array_slice($this->Remaining, 0)));
|
||||
return DBField::create("HTMLText", $html);
|
||||
}
|
||||
|
||||
@ -563,7 +563,7 @@ class DocumentationViewer extends Controller {
|
||||
}
|
||||
}
|
||||
|
||||
$link = Controller::join_links($base, self::get_link_base(), $version, $lang, $module, $action);
|
||||
$link = Controller::join_links($base, self::get_link_base(), $module, $lang, $version, $action);
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
@ -15,21 +15,21 @@ class DocumentationPageTest extends SapphireTest {
|
||||
$page->setEntity($entity);
|
||||
|
||||
// single layer
|
||||
$this->assertStringEndsWith('en/testmodule/test', $page->Link(), 'The page link should have no extension and have a language');
|
||||
$this->assertStringEndsWith('testmodule/en/test', $page->Link(), 'The page link should have no extension and have a language');
|
||||
|
||||
$folder = new DocumentationPage();
|
||||
$folder->setRelativePath('sort');
|
||||
$folder->setEntity($entity);
|
||||
|
||||
// folder, should have a trailing slash
|
||||
$this->assertStringEndsWith('en/testmodule/sort/', $folder->Link());
|
||||
$this->assertStringEndsWith('testmodule/en/sort/', $folder->Link());
|
||||
|
||||
// second
|
||||
$nested = new DocumentationPage();
|
||||
$nested->setRelativePath('subfolder/subpage.md');
|
||||
$nested->setEntity($entity);
|
||||
|
||||
$this->assertStringEndsWith('en/testmodule/subfolder/subpage', $nested->Link());
|
||||
$this->assertStringEndsWith('testmodule/en/subfolder/subpage', $nested->Link());
|
||||
|
||||
// test with version.
|
||||
$entity = DocumentationService::register("versionlinks", BASE_PATH . "/sapphiredocs/tests/docs-2/", '1');
|
||||
@ -37,7 +37,7 @@ class DocumentationPageTest extends SapphireTest {
|
||||
$page->setRelativePath('test.md');
|
||||
$page->setEntity($entity);
|
||||
$page->setVersion('1');
|
||||
$this->assertStringEndsWith('1/en/versionlinks/test', $page->Link());
|
||||
$this->assertStringEndsWith('versionlinks/en/1/test', $page->Link());
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,6 +139,10 @@ HTML;
|
||||
'[link: api](api:DataObject)',
|
||||
$result
|
||||
);
|
||||
$this->assertContains(
|
||||
'[link: relative](mycontroller/cms/2.4/a-relative-file.md)',
|
||||
$result
|
||||
);
|
||||
|
||||
// Page in subfolder
|
||||
$page = new DocumentationPage();
|
||||
@ -147,6 +151,11 @@ HTML;
|
||||
|
||||
$result = DocumentationParser::rewrite_relative_links($page->getMarkdown(), $page, 'mycontroller/cms/2.4/en/');
|
||||
|
||||
$this->assertContains(
|
||||
'[link: relative](mycontroller/cms/2.4/en/subfolder/subpage.md)',
|
||||
$result
|
||||
);
|
||||
|
||||
$this->assertContains(
|
||||
'[link: absolute index](mycontroller/cms/2.4/en/)',
|
||||
$result
|
||||
|
@ -41,7 +41,7 @@ class DocumentationViewerTest extends FunctionalTest {
|
||||
|
||||
function testGetModulePagesShort() {
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/'));
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/'));
|
||||
$pages = $v->getModulePages();
|
||||
|
||||
$arr = $pages->toArray();
|
||||
@ -52,7 +52,7 @@ class DocumentationViewerTest extends FunctionalTest {
|
||||
|
||||
function testGetModulePages() {
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/'));
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/'));
|
||||
$pages = $v->getModulePages();
|
||||
$this->assertEquals(
|
||||
array('sort/', 'subfolder/', 'test.md'),
|
||||
@ -69,9 +69,9 @@ class DocumentationViewerTest extends FunctionalTest {
|
||||
|
||||
$links = $pages->column('Link');
|
||||
|
||||
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/sort/', $links[0]);
|
||||
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/subfolder/', $links[1]);
|
||||
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/test', $links[2]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/sort/', $links[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/', $links[1]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/test', $links[2]);
|
||||
|
||||
// Children
|
||||
$pagesArr = $pages->toArray();
|
||||
@ -96,44 +96,44 @@ class DocumentationViewerTest extends FunctionalTest {
|
||||
$child2Links = $children->column('Link');
|
||||
$subpage = $children->First();
|
||||
|
||||
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/subfolder/subpage', $child2Links[0]);
|
||||
$this->assertStringEndsWith('2.4/en/DocumentationViewerTests/subfolder/subsubfolder/', $child2Links[1]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/subpage', $child2Links[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/subsubfolder/', $child2Links[1]);
|
||||
}
|
||||
|
||||
function testCurrentRedirection() {
|
||||
$response = $this->get('dev/docs/3.0/en/DocumentationViewerTests/test');
|
||||
$response = $this->get('dev/docs/DocumentationViewerTests/en/3.0/test');
|
||||
|
||||
$this->assertEquals(301, $response->getStatusCode());
|
||||
$this->assertEquals(
|
||||
Director::absoluteBaseURL() . 'dev/docs/current/en/DocumentationViewerTests/test/',
|
||||
Director::absoluteBaseURL() . 'dev/docs/DocumentationViewerTests/en/test/',
|
||||
$response->getHeader('Location'),
|
||||
'Redirection to current on page'
|
||||
);
|
||||
|
||||
$response = $this->get('dev/docs/3.0/en/DocumentationViewerTests/');
|
||||
$response = $this->get('dev/docs/DocumentationViewerTests/en/3.0');
|
||||
$this->assertEquals(301, $response->getStatusCode());
|
||||
$this->assertEquals(
|
||||
Director::absoluteBaseURL() . 'dev/docs/current/en/DocumentationViewerTests/',
|
||||
Director::absoluteBaseURL() . 'dev/docs/DocumentationViewerTests/en/',
|
||||
$response->getHeader('Location'),
|
||||
'Redirection to current on index'
|
||||
);
|
||||
|
||||
$response = $this->get('dev/docs/2.3/en/DocumentationViewerTests/');
|
||||
$response = $this->get('dev/docs/DocumentationViewerTests/en/2.3');
|
||||
$this->assertEquals(200, $response->getStatusCode(), 'No redirection on older versions');
|
||||
}
|
||||
|
||||
function testUrlParsing() {
|
||||
// Module index
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.3/en/DocumentationViewerTests/test'));
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.3/test'));
|
||||
$this->assertEquals('2.3', $v->getVersion());
|
||||
$this->assertEquals('en', $v->getLang());
|
||||
$this->assertEquals('DocumentationViewerTests', $v->module);
|
||||
$this->assertEquals(array('test'), $v->Remaining);
|
||||
|
||||
|
||||
// Module index without version and language. Should pick up the defaults
|
||||
$v2 = new DocumentationViewer();
|
||||
$response = $v2->handleRequest(new SS_HTTPRequest('GET', 'en/DocumentationViewerTests/test'));
|
||||
$response = $v2->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/test'));
|
||||
|
||||
$this->assertEquals('3.0', $v2->getVersion());
|
||||
$this->assertEquals('en', $v2->getLang());
|
||||
@ -143,7 +143,7 @@ class DocumentationViewerTest extends FunctionalTest {
|
||||
// Overall index
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', ''));
|
||||
$this->assertEquals('current', $v->getVersion());
|
||||
$this->assertEquals('', $v->getVersion());
|
||||
$this->assertEquals('en', $v->getLang());
|
||||
$this->assertEquals('', $v->module);
|
||||
$this->assertEquals(array(), $v->Remaining);
|
||||
@ -152,35 +152,35 @@ class DocumentationViewerTest extends FunctionalTest {
|
||||
function testBreadcrumbs() {
|
||||
// Module index
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/'));
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4'));
|
||||
$crumbs = $v->getBreadcrumbs();
|
||||
|
||||
$this->assertEquals(1, $crumbs->Count());
|
||||
$crumbLinks = $crumbs->column('Link');
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/', $crumbLinks[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/', $crumbLinks[0]);
|
||||
|
||||
// Subfolder index
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/'));
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/'));
|
||||
$crumbs = $v->getBreadcrumbs();
|
||||
$this->assertEquals(2, $crumbs->Count());
|
||||
$crumbLinks = $crumbs->column('Link');
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/', $crumbLinks[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/subfolder/', $crumbLinks[1]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/', $crumbLinks[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/', $crumbLinks[1]);
|
||||
|
||||
// Subfolder page
|
||||
$v = new DocumentationViewer();
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', '2.4/en/DocumentationViewerTests/subfolder/subpage'));
|
||||
$response = $v->handleRequest(new SS_HTTPRequest('GET', 'DocumentationViewerTests/en/2.4/subfolder/subpage'));
|
||||
$crumbs = $v->getBreadcrumbs();
|
||||
$this->assertEquals(3, $crumbs->Count());
|
||||
$crumbLinks = $crumbs->column('Link');
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/', $crumbLinks[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/subfolder/', $crumbLinks[1]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/subfolder/subpage/', $crumbLinks[2]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/', $crumbLinks[0]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/', $crumbLinks[1]);
|
||||
$this->assertStringEndsWith('DocumentationViewerTests/en/2.4/subfolder/subpage/', $crumbLinks[2]);
|
||||
}
|
||||
|
||||
function testRouting() {
|
||||
$response = $this->get('dev/docs/2.4/en/DocumentationViewerTests/test');
|
||||
$response = $this->get('dev/docs/DocumentationViewerTests/en/2.4/test');
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->assertContains('english test', $response->getBody(), 'Toplevel content page');
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
[link: absolute index](/)
|
||||
[link: absolute index with name](/index)
|
||||
[link: relative index](../)
|
||||
[link: relative](../subfolder/subpage.md)
|
||||
[link: relative multiline
|
||||
](../subfolder/subpage.md)
|
||||
[link: relative parent page](../test)
|
||||
[link: absolute parent page](/test)
|
||||
|
||||
![relative image link](_images/image.png)
|
||||
![parent image link](../_images/image.png)
|
||||
![absolute image link](/_images/image.png)
|
||||
![absolute image link](/_images/image.png)
|
||||
|
@ -9,6 +9,8 @@ test
|
||||
[link: with anchor](/test#anchor)
|
||||
[link: http](http://silverstripe.org)
|
||||
[link: api](api:DataObject)
|
||||
[link: relative](../a-relative-file.md)
|
||||
|
||||
[api:DataObject::$has_one]
|
||||
|
||||
:::php
|
||||
|
Loading…
Reference in New Issue
Block a user