Doing things only to some pages

Estimated reading time: 4 minutes.
Last update:

Soupault is meant to be a website generator for Web 1.0. One of the key freedoms the Web 2.0 approach took away is the freedom to make different pages look different. To live up to the Web 1.0-friendly promise, a tool must make it easy to do again. Soupault includes a number of features to make it easier.

Omitting widget's target from the page

First of all, as already mentioned, if a widget has a target selector, it will only run if it finds an element matching that selector. If there's no element where it could insert its output, it will do nothing. In the functional programming jargon, widgets are “lazily evaluated”.

For example, suppose you have this config for footnotes:

[widgets.footnotes]
  widget = "footnotes"

  selector = "div#footnotes"

  footnote_selector = ".footnote"
  footnote_link_class = "footnote"
  back_links = true
  link_id_prepend = "footnote-"
  back_link_id_append = "-ref"

If you want footnotes in every page, you can include a <div id="footnotes"> in templates/main.html and never have to think about it again (fun fact: that div needs not be at the bottom of the page, for a practical joke you can place it at the top or in the middle).

However, if you want it only in some pages, you can omit that div from the template, and insert it only in pages where you want footnotes.

Limiting widgets to specific pages

Omitting widget's target from a page is not always an option, or at least not the best option. Sometimes the target is too generic and cannot be omitted. For example, if you want to add a custom CSS style, using a link tag in the head, you'd have to leave the template to just <html> </html>, which is a very bad option for websites with more or less uniform-looking pages, since you'd end up with a lot of redundant code in the page content files.

This is why soupault has options for explicitly limiting widgets to certain pages or sections (i.e. subdirectories). For example, suppose you have a separate file with site news in templates/news.html that you only want to include in the main page of your website (i.e. site/index.html. You can do it by adding a page = "index.html" option to the widget config:

[widgets.site-news]
  page = "index.html"

  widget = "include"
  file = "templates/news.html"
  selector = "body"

You can also specify more than one page there. For example, this is how you could apply a special CSS style to cv.html and about.html:

[widgets.special-style]
  page = ["cv.html", "about.html"]

  widget = "insert_html"
  html = '<link rel="stylesheet" type="text/css" href="/special.css">'
  selector = "head"

I'm using single quotes for the HTML string here because they allows you to write double quotes inside strings without escaping.

You can also apply a widget to all pages in one or more sections using the section option. This is how you can do something to all pages in blog/:

[widgets.some-widget]
  section = "blog/"

  ...

If this is not flexible enough, you can use a regular expression, that option is called regex. The syntax is mostly Perl-compatible, but without backtracking support.

You can find a live example in my personal website config. The page in question, baturin.org/tools/bnfgen/ is a web application for playing with formal grammars, and it's a 90Kbyte JS file. No other page needs that file, so including it in every page would cause every visitor to download 90K of useless JS. That's why it's limited only to its own page with a regex option (it could use page instead, but that website doubles as a test suite for soupault dev builds, and I needed to use the regex option somewhere).

Excluding pages from widgets

Each of those options has a negative counterpart that allows you to do something to all but some of your pages. Those options care called exclude_page, exclude_section, and exclude_regex.

This is how you can set a style for every page except your main page:

[widgets.common-style]
  exclude_page = "index.html"

  widget = "insert_html"
  html = '<link rel="stylesheet" type="text/css" href="/common.css">'
  selector = "head"