mirror of
https://github.com/silverstripe/silverstripe-docsviewer
synced 2024-10-22 09:05:56 +00:00
ENHANCEMENT: Automatic (and manual) hash link generation for headlines done in server-side
This commit is contained in:
parent
04e7b89b66
commit
257c833e86
@ -15,6 +15,8 @@ class DocumentationParser {
|
|||||||
*/
|
*/
|
||||||
static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s';
|
static $api_link_base = 'http://api.silverstripe.org/search/lookup/?q=%s&version=%s&module=%s';
|
||||||
|
|
||||||
|
static $heading_counts = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a given path to the documentation for a file. Performs a case insensitive
|
* Parse a given path to the documentation for a file. Performs a case insensitive
|
||||||
* lookup on the file system. Automatically appends the file extension to one of the markdown
|
* lookup on the file system. Automatically appends the file extension to one of the markdown
|
||||||
@ -39,6 +41,7 @@ class DocumentationParser {
|
|||||||
$md = self::rewrite_image_links($md, $page);
|
$md = self::rewrite_image_links($md, $page);
|
||||||
$md = self::rewrite_relative_links($md, $page, $baselink);
|
$md = self::rewrite_relative_links($md, $page, $baselink);
|
||||||
$md = self::rewrite_api_links($md, $page);
|
$md = self::rewrite_api_links($md, $page);
|
||||||
|
$md = self::rewrite_heading_anchors($md, $page);
|
||||||
// $md = self::rewrite_code_blocks($md, $page);
|
// $md = self::rewrite_code_blocks($md, $page);
|
||||||
|
|
||||||
require_once('../sapphiredocs/thirdparty/markdown.php');
|
require_once('../sapphiredocs/thirdparty/markdown.php');
|
||||||
@ -187,6 +190,51 @@ class DocumentationParser {
|
|||||||
return $md;
|
return $md;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static function rewrite_heading_anchors($md, $page) {
|
||||||
|
$re = '/
|
||||||
|
\#+(.*)
|
||||||
|
/x';
|
||||||
|
$md = preg_replace_callback($re, array('DocumentationParser', '_rewrite_heading_anchors_callback'), $md);
|
||||||
|
|
||||||
|
return $md;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function _rewrite_heading_anchors_callback($matches) {
|
||||||
|
$heading = $matches[0];
|
||||||
|
$headingText = $matches[1];
|
||||||
|
|
||||||
|
if(preg_match('/\{\#.*\}/', $headingText)) return $heading;
|
||||||
|
|
||||||
|
if(!isset(self::$heading_counts[$headingText])) {
|
||||||
|
self::$heading_counts[$headingText] = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self::$heading_counts[$headingText]++;
|
||||||
|
$headingText .= "-" . self::$heading_counts[$headingText];
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf("%s {#%s}", preg_replace('/\n/', '', $heading), self::generate_html_id($headingText));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an html element id from a string
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
static function generate_html_id($title) {
|
||||||
|
$t = $title;
|
||||||
|
$t = str_replace('&','-and-',$t);
|
||||||
|
$t = str_replace('&','-and-',$t);
|
||||||
|
$t = ereg_replace('[^A-Za-z0-9]+','-',$t);
|
||||||
|
$t = ereg_replace('-+','-',$t);
|
||||||
|
$t = trim($t, '-');
|
||||||
|
|
||||||
|
return $t;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves all relative links within markdown.
|
* Resolves all relative links within markdown.
|
||||||
*
|
*
|
||||||
@ -367,4 +415,5 @@ class DocumentationParser {
|
|||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
$('#left-column h1, #left-column h2, #left-column h3, #left-column h4').each(function(i) {
|
$('#left-column h1, #left-column h2, #left-column h3, #left-column h4').each(function(i) {
|
||||||
var current = $(this);
|
var current = $(this);
|
||||||
current.attr('id', 'title' + i);
|
|
||||||
toc += '<li class="' + current.attr("tagName").toLowerCase() + '"><a id="link' + i + '" href="'+ window.location.href +'#title' + i + '" title="' + current.html() + '">' + current.html() + '</a></li>';
|
toc += '<li class="' + current.attr("tagName").toLowerCase() + '"><a id="link' + i + '" href="'+ window.location.href +'#title' + i + '" title="' + current.html() + '">' + current.html() + '</a></li>';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -64,6 +64,44 @@ class DocumentationParserTest extends SapphireTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testHeadlineAnchors() {
|
||||||
|
$page = new DocumentationPage(
|
||||||
|
'test.md',
|
||||||
|
new DocumentationEntity('mymodule', '2.4', BASE_PATH . '/sapphiredocs/tests/docs/'),
|
||||||
|
'en',
|
||||||
|
'2.4'
|
||||||
|
);
|
||||||
|
|
||||||
|
$result = DocumentationParser::rewrite_heading_anchors($page->getMarkdown(), $page);
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Heading one {#Heading-one}
|
||||||
|
|
||||||
|
# Heading with custom anchor {#custom-anchor} {#Heading-with-custom-anchor-custom-anchor}
|
||||||
|
|
||||||
|
## Heading two {#Heading-two}
|
||||||
|
|
||||||
|
### Heading three {#Heading-three}
|
||||||
|
|
||||||
|
## Heading duplicate {#Heading-duplicate}
|
||||||
|
|
||||||
|
## Heading duplicate {#Heading-duplicate-2}
|
||||||
|
|
||||||
|
## Heading duplicate {#Heading-duplicate-3}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
$this->assertContains('# Heading one {#Heading-one}', $result);
|
||||||
|
$this->assertContains('# Heading with custom anchor {#custom-anchor}', $result);
|
||||||
|
$this->assertNotContains('# Heading with custom anchor {#custom-anchor} {#Heading', $result);
|
||||||
|
$this->assertContains('# Heading two {#Heading-two}', $result);
|
||||||
|
$this->assertContains('# Heading three {#Heading-three}', $result);
|
||||||
|
$this->assertContains('## Heading duplicate {#Heading-duplicate}', $result);
|
||||||
|
$this->assertContains('## Heading duplicate {#Heading-duplicate-2}', $result);
|
||||||
|
$this->assertContains('## Heading duplicate {#Heading-duplicate-3}', $result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function testRelativeLinks() {
|
function testRelativeLinks() {
|
||||||
// Page on toplevel
|
// Page on toplevel
|
||||||
$page = new DocumentationPage(
|
$page = new DocumentationPage(
|
||||||
|
@ -20,3 +20,17 @@ Normal text after code block
|
|||||||
|
|
||||||
code block
|
code block
|
||||||
without formatting prefix
|
without formatting prefix
|
||||||
|
|
||||||
|
# Heading one
|
||||||
|
|
||||||
|
# Heading with custom anchor {#custom-anchor}
|
||||||
|
|
||||||
|
## Heading two
|
||||||
|
|
||||||
|
### Heading three
|
||||||
|
|
||||||
|
## Heading duplicate
|
||||||
|
|
||||||
|
## Heading duplicate
|
||||||
|
|
||||||
|
## Heading duplicate
|
||||||
|
Loading…
x
Reference in New Issue
Block a user