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