# OD-1307 - Investigate Anchor Links Issue
## Tasks list
* [x] [Fix Header ids not being generated](#Fix-Header-Ids-not-being-generated) - Fixed
* [x] [Fix CSS issues with headers scrolling out of view](#Headers-scrolling-out-of-view)
## Header Ids not being generated
The issue was that when headers within markdown files are referenced, the links don't work. For example:
This markdown
```md
# Esse ipse elige
## Premebat erit
**Internal Links:**
- [Esse ipse elige](#esse-ipse-elige)
- [Premebat erit](#premebat-erit)
```
returns the html as:
```html
<h1>Esse ipse elige</h1>
<h2>Premebat erit</h2>
<p><strong>Internal Links:</strong></p>
<ul>
<li><a href="#esse-ipse-elige">Esse ipse elige</a></li>
<li><a href="#premebat-erit">Premebat erit</a></li>
```
The anchor links are actually being rendered correctly, but there are no header ids to reference.
The issue was with the `render_markdown` helper in core ckan: https://github.com/ckan/ckan/blob/master/ckan/lib/helpers.py#L2218-L2244 which uses the **[markdown python library](https://python-markdown.github.io/)**. It doesn't render the header ids by default. It however has a [**TOC** extension](https://python-markdown.github.io/extensions/toc/) that can be called which renders the header ids.
By defining a new `render_markdown` helper to override the default ckan helper, the header ids were now rendered.
Adding this to the Ed extension [`helpers.py`](https://github.com/CivicActions/ckanext-ed/blob/master/ckanext/ed/helpers.py) fixes this issue.
```python=
def render_markdown(data, auto_link=True, allow_html=False):
''' Returns the data as rendered markdown
:param auto_link: Should ckan specific links be created e.g. `group:xxx`
:type auto_link: bool
:param allow_html: If True then html entities in the markdown data.
This is dangerous if users have added malicious content.
If False all html tags are removed.
:type allow_html: bool
'''
if not data:
return ''
if allow_html:
data = h.markdown(data.strip(), extensions=['toc'])
else:
data = h.RE_MD_HTML_TAGS.sub('', data.strip())
# Allow header ids
allowed_headers = {
'h1': ['id'], 'h2': ['id'], 'h3': ['id'], 'h4': ['id'], 'h5': ['id'], 'h6': ['id']
}
h.MARKDOWN_ATTRIBUTES.update(allowed_headers)
h.MARKDOWN_TAGS.update(['h1', 'h2', 'h3', 'h4', 'h5', 'h6'])
data = h.bleach_clean(
h.markdown(data, extensions=['toc']), strip=True,
tags=h.MARKDOWN_TAGS, attributes=h.MARKDOWN_ATTRIBUTES)
# tags can be added by tag:... or tag:"...." and a link will be made
# from it
if auto_link:
data = h.html_auto_link(data)
return h.literal(data)
```
After the fix, this markdown:
```md
# Esse ipse elige
## Premebat erit
**Internal Links:**
- [Esse ipse elige](#esse-ipse-elige)
- [Premebat erit](#premebat-erit)
```
would then return the html as:
```html
<h1 id="esse-ipse-elige">Esse ipse elige</h1>
<h2 id="premebat-erit">Premebat erit</h2>
<p><strong>Internal Links:</strong></p>
<ul>
<li><a href="#esse-ipse-elige">Esse ipse elige</a></li>
<li><a href="#premebat-erit">Premebat erit</a></li>
```
## Headers scrolling out of view
After getting the header ids to render, they still don't scroll into view correctly.
For example, for a markdown with header:
```
<h1 id="esse-ipse-elige">Esse ipse elige</h1>
```
It scrolls to high and goes out of view:

It should instead look like this:
