---
# System prepended metadata

title: OD-1307 - Investigate Anchor Links Issue

---

# 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:

![](https://i.imgur.com/H05IMqV.png)

It should instead look like this: 

![](https://i.imgur.com/RFFdneU.png)
