Creating a Category Based Collapsible List
↳Part of: Advanced Customization of Jekyll

  10 Apr 2017


The idea behind this project was to have a collapsible list, containing links to specific anchors on the post page. This would make the site a bit easier to use and better show off the post series. Despite this, I still wished to keep functionality for those disabling JavaScript.

Warning: This feature shall require JavaScript. You could rewrite this in Liquid, however the Collapse feature used requires JavaScript, thus making a fully Liquid solution not possible (and needlessly complicated).

TL;DR

Here is the code that I used to generate the sidebar for this specific site. Also this post assumes that all posts have a series tag, which contains their category name in long form (alternatives below). Very likely you shall need to customize the CSS, as this CSS is pretty hard coded to my needs.

HTML Anchor


<a id="noscript" href="/posts.html" data-toggle="collapse">Blog Series</a>
<script>document.getElementById("noscript").href="#postCategories";</script>

<div id="postCategories" class="collapse">
<ul id="replace">
  <li>JavaScript Failed</li>
</ul>
</div>

JavaScript


<script>
  var catArray = [];
  var list = "";

  {% for pg in site.posts %}
    var found=false;
    for(i = 0; i<catArray.length;i++){
      if(catArray[i]=="{{pg.categories}}") found=true;
    }
    if(!found){
      catArray.push("{{pg.categories}}");
      list='<li><a href="{{site.baseurl}}/posts.html#{{pg.categories}}">{{pg.series}}</a></li>'+list;
    }

  {% endfor %}

  document.getElementById('replace').innerHTML = list;

</script>

HTML Anchor

Desktop

<a id="desktop_noscript" href="/posts.html" data-toggle="collapse">Blog Series</a>
<script>document.getElementById("desktop_noscript").href="#desktop_postCategories";</script>

<div id="desktop_postCategories" class="collapse">
<ul id="desktop_replace" style="padding-left: 55px">
  <li>JavaScript Failed</li>
</ul>
</div>

Mobile

<a id="mobile_noscript" href="/posts.html" data-toggle="collapse">Blog Series</a>
<script>document.getElementById("mobile_noscript").href="#mobile_postCategories";</script>

<div id="mobile_postCategories" class="collapse">
<ul id="mobile_replace" style="padding-left: 55px">
  <li>JavaScript Failed</li>
</ul>
</div>

JavaScript


<script>
  var catArray = [];
  var list = "";

  {% for pg in site.posts %}
    var found=false;
    for(i = 0; i<catArray.length;i++){
      if(catArray[i]=="{{pg.categories}}") found=true;
    }
    if(!found){
      catArray.push("{{pg.categories}}");
      list='<li style="font-size: 13px; text-indent: 0;line-height: 15px; padding-bottom: 1px; padding-top: 2px;"><a href="{{site.baseurl}}/posts.html#{{pg.categories}}">{{pg.series}}</a></li>'+list;
    }

  {% endfor %}

  document.getElementById('desktop_replace').innerHTML = list;
  document.getElementById('mobile_replace').innerHTML = list;

</script>

Requirements and Limitations

For this project we shall be using the Collapse scripts provided by Bootstrap. Like all my other projects, I am assuming that we are using one Category per post and that there is a series tag, which contains the post’s Category in long form.

Alternatives to Series tag: As an alternative, you could have a JavaScript function that has an entry parameter of

HTML Portion

Creating the Anchor
<a id="desktop_noscript" href="/posts.html" data-toggle="collapse">Blog Series</a>
<script>document.getElementById("desktop_noscript").href="#postCategories";</script>

As we are working with a section that is JavaScript based, it would be sensible to take into account, those wishing to use NoScript or similar JavaScript blocking tools. Therefore, we shall define our Anchor giving a link to the posts.html page. If JavaScript is enabled, the following script shall replace the anchor’s href to collapse/expand the following list.

The data-toggle tag in the anchor, shall allow us to toggle whether or not the object ID’d as #postCategories is shown.

Note for Herring-Cove Users: HC has two different navigation bars, so you are required to copy the code once for desktop and once for mobile/small screen devices. This is the reason behind the naming.

Collapsible List
<div id="postCategories" class="collapse">
<ul id="desktop_replace" style="padding-left: 55px">
  <li>JavaScript Failed</li>
</ul>
</div>

Now seeing as we have created an anchor, we need to create the list in which we shall insert objects.

First of all, we shall place this list in a collapsible div. The ID of this div, shall be the same as the one referenced in the script’s href (excluding the # of course).

Next you shall define a list of your choosing. In this case, I have chosen to use an unordered list (ul). You must give it a ID, to allow it to replaced by the JavaScript. The style elements I have included help me position the list correctly. You most likely will not need this.

Out of personal preference, I have added a List Item which says “JavaScript Failed”, to help with debugging. This is not required, but may prove helpful.

JavaScript


<script>
  var catArray = [];
  var list = "";

  {% for pg in site.posts %}
    var found=false;
    for(i = 0; i<catArray.length;i++){
      if(catArray[i]=="{{pg.categories}}") found=true;
    }
    if(!found){
      catArray.push("{{pg.categories}}");
      list='<li style="font-size: 13px; text-indent: 0;line-height: 15px; padding-bottom: 1px; padding-top: 2px;"><a href="{{site.baseurl}}/posts.html#{{pg.categories}}">{{pg.series}}</a></li>'+list;
    }

  {% endfor %}

  document.getElementById('desktop_replace').innerHTML = list;

  //If needed, uncomment the following line
  //document.getElementById('mobile_replace').innerHTML = list;

</script>

The way this works is that you have an Array of categories (catArray) and a String list, which contains the final HTML code you are going to insert.

You will be going through each post and checking if its category is already within catArray. If it is not, then it shall be added to catArray. In addition, a list element containing the series name (so the long form of the category name), as well as linking to its respective anchor on the posts.html page.

Finally at the end of the script, we shall insert the text into the desktop_replace and mobile_replace unlisted lists.

Note: Style elements are required for my specific theme. You will likely need your own CSS to make this look appropriately.

Sample

Here is a demo version of the feature.

Click Here


Creative Commons LicenseThe content of this site's posts are licensed under a Creative Commons Attribution-NonCommercial 4.0 International License. Read More
comments powered by Disqus