<ol> tag doesn't increment from 1 and stays at 1 while using in a 'for' loop in HTML - html

Firstly, I don't know anything about HTML. I am trying to build a website using Jekyll and found a template for the website, to which I am making modifications.
I have the following code:
{% for publi in site.data.publist %}
{% assign even_odd = number_printed | modulo: 2 %}
{% if even_odd == 0 %}
<div class="row">
{% endif %}
<div>
<ol>
<li>{{ publi.title }}</li>
<!-- <img src="{{ site.url }}{{ site.baseurl }}/images/pubpic/{{ publi.image }}" class="img-responsive" width="33%" style="float: left" />
--> <p>{{ publi.description }}</p>
<p><em>{{ publi.authors }}</em></p>
<p><strong>{{ publi.link.display }}</strong></p>
<!-- <p class="text-danger"><strong> {{ publi.news1 }}</strong></p>
<p> {{ publi.news2 }}</p> -->
</ol>
</div>
{% assign number_printed = number_printed | plus: 1 %}
{% if even_odd == 1 %}
</div>
{% endif %}
{% endfor %}
There is a YAML file in the site.data.publist which has a number of members, each with different fields. The for loop helps to go through all the members of the YAML file.
As you can see in the code, I am using the <ol> tag in the for loop and I have used the <li> tag for the publi.title (a field in the members of the YAML file). But all I get is one repeating for all the members in the YAML file. I have attached the output I get.

As sirko mentioned in his comment, you are generating invalid HTML.
First of all, the <ol> may only contain li as direct children. So make sure to put everything else also within the li tag.
But your real problem is that you generate the ol tags within your loop. As mentioned in the comment, your output the contains multiple lists with one element each, not one list with n elements.
In order to change that, you have to move the ol outside of the for loop. (And then make sure you still generate valid HTML => see point 1.)

Related

Jekyll - If there is more then 1 post.tag for a blog post then display a message otherwise display the tag name

In Jekyll which uses the Liquid template language, I am on my blog page and I am displaying the latest 6 blog posts. For each post, I show the post date, name, excerpt, and the post url in a link.
I also want to be able to show the first tag of this post (for example, "Front-end development"). However, if there is more than 1 tag associated with the post, I want to display a fallback message saying "View tags", which toggles a dropdown with links to the other tags. If I can return an unordered list, that's fine, as I can take it from there.
This code doesn't work, but hopefully it illustrates what I'm trying to achieve:
{% for tag in post.tags %}
{% if tag.size > 1 %}
<a class="toggle-tag-list">View tags</a>
<ul class="tag-list hidden">
<li>tag 1</li>
<li>tag 2</li>
<li>tag 3</li>
</ul>
{% else %}
{{ tag }}
{% endif %}
{% endfor %}
Edited answer :
I saw that tag.url returns nothing and it's normal.
But, if you are using tag pages (by hand or with jekyll-paginate-v2), you already know their urls. You can craft something like I'm doing in this edit for href supposing that your tag pages urls are of the form /site.basurl/tag/tagname/.
Feel free to adapt the code.
You can try this :
{% if post.tags.size > 0 %}
{% if post.tags.size > 1 %}
<a class="toggle-tag-list">View tags</a>
<ul class="tag-list hidden">
{% for tag in post.tags %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
{% else %}
{{ post.tags.first }}
{% endif %}
{% endif %}

How to reference properties in liquid

I have a Jekyll template pulling in text from data objects.
eg.
{% for speaker_hash in site.data.2015.speakers %}
{% assign speaker = speaker_hash[1] %}
<li>
<div class="speaker">
<img class="head" src="/img/2015/speakers/sample.jpg">
<h2> {{ speaker.name}} </h2>
</div>
</li>
{% endfor %}
However I would like to have each page specify what year its for with a page.year property.
Is it possible to create the same for loop but specify the year dynamically?
eg
{% for speaker_hash in site.data.[page.year].speakers %}
Answer yes.
1 - Your page.year must be a string as hash indexes are strings. So in you front matter : year: '2015'
2 - Get speakers depending on page.year :
{% for speaker_hash in site.data[{{page.year}}].speakers %}

multiple arbitrary blocks in Jinja2 macros

I use both Jinja2 and Nunjucks (depending on the project), but have yet to figure out how to create reusable elements with multiple blocks containing arbitrary HTML. For example (pseudo-code):
{% macro item(class) %}
<article class="{{ class }}">
<h3>{{ caller(1) }}</h3>
<p>{{ caller(2) }}</p>
</article>
{% endmacro %}
{% call item %}
Hello <abbr title="...">world</abbr>!
{% ---- %}
lorem <em>ipsum</em> dolor <strong>sit</strong> amet
{% endcall %}
Passing the respective blocks' HTML as regular arguments (i.e. strings) to the macro seems unrealistic.
A less contrived example might be Bootstrap-style forms:
<div class="form-group">
<label for="{{ id }}" class="control-label">$label</label>
<input type="{{ type }}" id="{{ id }}">
<p class="help-block">$hint</p>
</div>
Here both $label and $hint might be arbitrary blocks of HTML - perhaps there might even be multiple fields, defined outside the macro.
What's the recommended approach here?
You might find this useful for re-usable HTML components:
https://github.com/mozilla/nunjucks/pull/277
Example:
{% include 'search-box.html.twig' with {placeholder: 'Search users'} %}
You can use embed tag of atpl template engine.
Example:
{% embed "teasers_skeleton.twig" %}
{# These blocks are defined in "teasers_skeleton.twig" #}
{# and we override them right here: #}
{% block label %}
Some content for the label box
{% endblock %}
{% block hint %}
Some content for the hint box
{% endblock %}
{% endembed %}

How to change the default order pages in Jekyll?

My blog is built with Jekyll on Github. In the navigation bar, the default order is Pages, Messages, About, Archives. I want to change the list to Pages, Archives, About, Messages. What should I do?
I think it is related to the code below
{% assign pages_list = site.pages %}
I think site.pages is what I should change, but I don't know how.
You can create custom order of your menu items like this:
In your pages front matter add the order field (you can name it as you prefer)
---
layout: default
published: true
title: Page title
order: 1
---
When getting pages, apply the 'sort' filter
{% assign sorted_pages = site.pages | sort:"order" %}
{% for node in sorted_pages %}
<li>{{node.title}}</li>
{% endfor %}
You'll end up with an ordered (ASC) list of pages, based on the 'order' field value you add to each page.
Update: Some ordering functionality seems to have been added to Jekyll: https://github.com/plusjade/jekyll-bootstrap/commit/4eebb4462c24de612612d6f4794b1aaaa08dfad4
Update: check out comment by Andy Jackson below – "name" might need to be changed to "path".
This seems to work for me:
{% assign sorted_pages = site.pages | sort:"name" %}
{% for node in sorted_pages %}
<li>{{node.title}}</li>
{% endfor %}
name is file name. I renamed pages to 00-index.md, 01-about.md etc. Sorting worked, but pages were generated with those prefixes, which looked ugly especially for 00-index.html.
To fix that I override permalinks:
---
layout: default
title: News
permalink: "index.html"
---
Sadly, this won't work with custom attributes, because they are not accessible as methods on Page class:
{% assign sorted_pages = site.pages | sort:"weight" %} #bummer
The order of your navbar menu is determined by the HTML template in _layout (which may be pulling in HTML fragments from _includes.
It sounds like your navbar is being programatically generated from the list of pages provided in site.pages using the liquid code
{% assign pages_list = site.pages %}
If you have only a small number of pages, you may prefer to just write the list out manually. site.pages is Jekyll's alphabetical list of all pages. Nothing stops you from just hardcoding this instead:
<div class="navbar" id="page-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="/">EverCoding.net</a>
<ul class="nav">
<li>Pages</li>
<li>Archive</li>
<li>About</li>
<li>Messages</li>
Whereas I'm guessing at the moment you have that list generated programmatically, perhaps by following the way Jekyll-bootstrap does with liquid code:
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="{{ HOME_PATH }}">{{ site.title }}</a>
<ul class="nav">
{% assign pages_list = site.pages %}
{% assign group = 'navigation' %}
{% include JB/pages_list %}
</ul>
</div>
</div>
</div>
The liquid code in this second example is handy if you really want to determine the menu each time, but if you have a static menu in a static order you are probably best coding it by hand as in my first example, rather than modifying the liquid code to sort.
If you could link to the Jekyll source, rather than the published blog, we could be more specific.
I'm using Jekyll v2.5.3 and you can also number your actual markdown files (order them that way) and since you're using the Front Matter block you can still keep the titles and permalinks as you want them.
The parser will order your page links that way.
I.e.:
01_about.md
02_photos.md
03_projects.md
99_contact.md
I made pages.yml file in the _data directory it is look like similar:
- url: pages/test.html
title: Pages
group: navigation
- url: pages/front.html
title: Front
group: navigation
And I changed the default.html (from site.pages to site.data.pages):
<ul class="nav">
{% assign pages_list = site.data.pages %}
{% assign group = 'navigation' %}
{% include JB/pages_list %}
</ul>
And now I can use this yml file for the menu.
You could see the documentation: http://jekyll.tips/jekyll-casts/navigation/
There are good examples and explanations with navigation_weight.
---
layout: page
title: About
permalink: /about/
navigation_weight: 10
---
For minima:
<div>
{% assign navigation_pages = site.pages | sort: 'navigation_weight' %}
{% for p in navigation_pages %}
{% if p.navigation_weight %}
{% if p.title %}
<a class="page-link" href="{{ p.url | relative_url }}">{{ p.title | escape }}</a>
{% endif %}
{% endif %}
{% endfor %}
</div>
For minima theme
Put:
header_pages:
- pages.md
- archive.md
- about.md
- messages.md
in _config.yml to override default order. That's all.
Minima README:
Customize navigation links
This allows you to set which pages you want to appear in the
navigation area and configure order of the links.
For instance, to only link to the about and the portfolio page,
add the following to you _config.yml:
- about.md
- portfolio.md
You can see how it works in header.html file from minima _includes.
You were on the right path. You could sort by a custom variable named, say, 'order'.
In header.html insert and extra row:
{% assign pages_list = (site.pages | sort: 'order') %}
Then replace site.pages with pages_list in the for statement:
{% for my_page in pages_list %}
{% if my_page.title %}
<a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
{% endif %}
{% endfor %}
Then add 'order' into the YAML front matter for each page, and set it a suitable value:
---
layout: page
title: About
permalink: /about/
order: 0
---
The Jekyll Bootstrap 3 template requires that you include group navigation in the Jekyll header. Building on #Wojtek's answer, you can modify JB3's pages_list to use this group field to both filter, and sort.
Before calling pages_list, sort by group:
{% assign sorted_pages = site.pages | sort:"group" %}
Then, simply change one line in pages_list:
{% if group == null or group == node.group %} -> {% if group == null or node.group contains group %}
Now you can specify the group to be navigation-00, navigation-01, without having to rename your files or set up any permalinks, and you get sorting for free.
I made a simple plugin some time ago to sort pages according to a page_order array you can define your _config.yml:
pages_order: ['index', 'summary', 'overview', 'part1', 'part2', 'conclusion', 'notes']
It exposes page.prev and page.next in templates to allow navigation:
{% if page.prev %}
<a id="previous-page" href="{{page.prev}}.html">Previous</a>
{% endif %}
{% if page.next %}
<a id="next-page" href="{{page.next}}.html">Next</a>
{% endif %}
Note: Does not work on Github Pages.

how to get a sorted tags_list in jekyll

I'm using jekyll-bootstrap to maintain a blog on GitHub.
I'd like to have a sorted tags_list. The tag with the most posts comes first. Then I can have a display that shows the first tags with bigger font-size and last tags with smaller font-size. And I also want a splice function.
If in python/Jinja2, I'd like some code like this:
{% for tag in sorted_tags[:10] %}
<li style="font-size:{{ tag.count }}px;">{{ tag.name }}</li>
{% endfor %}
What's the equivalent implementation in ruby/jekyll?
This is how I'm sorting by the number of posts in a tag (descending), without any plugins (i.e. GitHub Pages compatible).
It also works when your tag names contain spaces; only , and : are forbidden characters (but you can easily change those).
{% capture counts_with_tags_string %}{% for tag in site.tags %}{{ tag[1] | size | prepend:"000000" | slice:-6,6 }}:{{ tag[0] }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
{% assign counts_with_tags = counts_with_tags_string | split:"," | sort | reverse %}
<ol>
{% for count_with_tag in counts_with_tags %}
{% assign tag = count_with_tag | split:":" | last %}
{% assign count = site.tags[tag] | size %}
<li>{{ tag }} ({{ count }})</li>
{% endfor %}
</ol>
It's super gross. What it does:
counts_with_tags_string is set to a string like 000005:first_tag,000010:second_tag,000002:third_tag. The zero-padded numbers are generated using the filter chain | prepend:"000000" | slice:-6,6.
This is split on commas and sorted lexicographically, which works because of the zero padding. The result is assigned to counts_with_tags.
Finally, we iterate over the elements and split each on : to find the original tag name. We could find the count in the same way, but because it's zero padded, it's easier to look it up using site.tags[tag] | size instead.
I thought that the tags array is sorted. Assuming so, you can do this:
{% for tag in site.tags %}
<li style="font-size: {{ tag[1].size }}px">{{ tag[0] }}</li>
{% endfor %}
That feels a little hacky, but it should work. Unfortunately, Liquid doesn't currently allow you to sort arrays within your templates. If you want to do any sorting on the array, you'd probably have to write a plugin to do so - it shouldn't be too complex. In fact, there's an existing plugin for sorting accessors that may do it: https://github.com/krazykylep/Jekyll-Sort
I only needed to do this in one place, on the page where my list of Tags was listed, so I wrote it as a Jekyll filter:
tag_index.html
<h2>Posts by Tag</h2>
<ul class="tags-list">
{{ site.tags | render_tags_list }}
</ul>
_plugins/filters.rb
module Jekyll
module Filters
def render_tags_list(tags)
sorted_tags = tags.keys.sort_by! { |tag| tag.downcase }
str = ''
sorted_tags.each { |tag|
str << '<li>' + tags[tag].size.to_s + ' - ' + tag + '</li>'
}
str
end
end
end
You could certainly just allow the filter to return sorted_tags above if you wanted to keep a better separation between "view" logic and programming logic, but my case was very simple. Trying to re-access a hash value by a specific key using Liquid templating wasn't a very concise process, or maybe I was just doing it wrong, but was much easier in Ruby.
I'm hosting my blog on github and wanted a solution to sorting a tag list that did not involve any jekyll plugins since Github doesn't allow for custom plugins (jekyll bootstrap attempts this as well). My post here doesn't really answer the question since I sort by tag name, and NOT by size. You can adapt this method to output the tag size as well in the string and then do some fancier spliting to get a different sort order (but it will be messy)
I was able to do this with the following code:
{% capture tagString %}{% for tag in site.tags %}{{ tag[0] }}{% unless forloop.last %}|{% endunless %}{% endfor %}{% endcapture %}
{% assign tags = tagString | split: '|' | sort: 'downcase' %}
<div id="cloud">
{% for tag in tags %}
{% assign number = site.tags[tag].size %}
{% assign slug = tag | downcase | replace: ' ', '_' %}
<span class="{% if number == 1 %}small{% elsif number <= 5 %}medium{% elsif number <= 10 %}large{% else %}huge{% endif %}">
{{ tag | downcase }}
</span>
{% endfor %}
</div>
It's kind of odd since I capture a string of tags (using | as separator) and then use that to create an array. After that point (in the loop) I can refer to the tag as tag and the list of sites that use that tag as site.tags[tag].
I use this on my blog:
https://github.com/kelsin/kelsin.github.io/blob/master/tags/index.html
The rest of the code is just how I've chosen to make a tag cloud on my tag page. Hope this helps someone else looking for a solution (without plugins)!