Reusing Contents

User Guide → Reusing Contents

Reusing Contents

MarkBind is highly-optimized for content reuse. It offers several mechanisms to provide readers with many variations of the content while minimizing duplication at source file level. As a result, instead of creating a one-size-fits-all site, MarkBind can create a site in which readers can chart their own path of reading.

User Guide → Reusing Contents → Variables

Variables

Nunjucks variables are ideal for reusing small bits of code in multiple places; you can define a variable to represent the code bit in question and reuse it anywhere in the site by referring to the variable instead of duplicating the code bit.

MarkBind does not aim to alter the already robust variable features of nunjucks, but provides several extensions to it.

Global Variables

Global variables are to be defined in the _markbind/variables.md file. Each variable must have an name and the value can be any MarkBind-compliant code fragment. The name should not contain - and .. For example, search-option and search.options are not allowed.

The variables declared here are available from anywhere in the code base.

Example Here's how you can define two variables year and options:

<variable name="year">2018</variable>

<variable name="options">
* yes
* no
* maybe
</variable>

To include a variable value in your code, give the variable id enclosed in Nunjucks' double curly braces syntax.

Example The year was {{ year }}. The year was 2018.

Global variables (_markbind/variables.md) will take precedence over any variables set via Nunjucks' tags (e.g. {% set %}).

Built-in Global Variables

MarkBind also provides a number of built-in variables.

Variable Notes Example Output
baseUrl Represents the root directory of the site on the server, as configured in your site configuration file.
Used for specifying intra-site links.
If baseUrl is specified as userGuide/:

<img src="{{baseUrl}}/images/logo.png" />
<img src="userGuide/images/logo.png" />
timestamp The time stamp that indicates when the page was generated.

The default values of "timeZone" and "locale" are "UTC" and "en-GB" respectively.
The following example showcases the use of the "Asia/Singapore" time zone.

Page generated at: {{timestamp}}
Page generated at: Sun, 18 Jul 2021, 7:48:04 UTC
MarkBind The MarkBind version in use, linked to the MarkBind website. Page generated by: {{MarkBind}} Page generated by: MarkBind 3.0.6

Importing variables from other external file formats

You can also source variables from external files using MarkBind's {% ext varName = "filepathToFile" %} Nunjucks extension. This is useful if you have external datasets you want to display in your site!

To do so, assign a root variable name (varName) to the file path from the similar to how you assign filepaths for other Nunjucks tagsroot directory of the site. You may then access the file's variables using dot varName.xx or array varName[i] syntax, depending on the file's contents.

Example

CODE:

Displaying a student scoreboard stored as JSON
{% ext studentScoreboard = "userGuide/syntax/extra/scoreboard.json" %}

Student Number | Score | Rank
:----- | :-------: | ----
{% for student in studentScoreboard.students -%}
{{ student.number }} | {{ student.score }} | {{ student.rank }}
{% endfor %}

<small>Last updated at {{ studentScoreboard.lastUpdated }}</small>

Json file used in example


OUTPUT:

Student Number Score Rank
A1234567X 87 / 100 1
A1234123U 60 / 100 3
A9876543L 76 / 100 2

Last updated at 21 November, 2020


Example

CODE:

Displaying a student scoreboard stored as CSV
{% ext studentScoreboard = "userGuide/syntax/extra/scoreboard.csv" %}

Student Number | Score | Rank
:----- | :-------: | ----
{% for student in studentScoreboard -%}
{{ student.number }} | {{ student.score }} | {{ student.rank }}
{% endfor %}

CSV file used in example


If you do not want to have a header row, you can specify it by appending a noHeader option at the end of the variable declaration. In this example, it should be {% ext studentScoreboard = "userGuide/syntax/extra/scoreboard.csv", noHeader %} . Elements have to be accessed using the [] operator (i.e. using student[0] to access student number instead of student.number).

OUTPUT:

Student Number Score Rank
A1234567X 87 / 100 1
A1234123U 60 / 100 3
A9876543L 76 / 100 2

Only .json and .csv files are supported for now.

Global variables:

_markbind/variables.md:

<variable name="year">2018</span>

The year was {{ year }}.


User Guide → Reusing Contents → Includes

Includes

MarkBind has a powerful <include> mechanism which allows you to create documents by combining other content fragments.

You can use <include> tag to include another markdown or HTML document into the current document.

Example Including text from a tip2.md in another file.

Tip 1. ...
<include src="tips/tip2.md" />
Tip 3. ...

You can <include> a fragment of a file by specifying the #fragment-id at the end of the src attribute value, provided the fragment is wrapped in a <div>/<span>/<seg> tag with the matching id.

Example Including a fragment from a file:

Some text
<include src="docs/tips.md#tip-1" />
Some other text

docs/tips.md:

...
<div id="tip-1" />
  Tip 1. ...
  ...
</div>
Tip 2. ...

When setting the id of a fragment, be careful not to clash with heading anchor IDs auto-generated by MarkBind. For example, if you have a heading ## Some Useful Tips, MarkBind will auto-generate an ID some-useful-tips for that heading.

The <include> tag works for any MarBind source file including the font matter section but it may not work in some special files such as the _markbind/variables.md.

Attributes:

  • src: specify the source file path.
  • inline (optional): make the included result an inline element. (wrapped in <span> tag). e.g.,
    The title is <include src="../docs/summary.md#title" inline /> while ...
    
  • optional (optional): include the file/fragment only if it exists i.e., there will be no error message if the file/fragment does not exist. e.g.,
    <include src="UserStories.md" optional />
    
  • trim (optional): remove leading and trailing whitespace and newlines from the document before including.
    <include src="UserStories.md#epic" trim />
    
  • omitFrontmatter (optional): omit the front matter of the file/fragment from being included (if any).
    
    

The <include> mechanism can be used inside any MarkBind source file (even inside the front matter section) but it will not work inside some special files such as the _markbind/variables.md.

<include> Inside an Included File

Although the src attribute of an <include> is given relative to the current directory, it is converted to an absolute value before the i.e., the file containing the <include>host file is included from another file.

Example Suppose you have a MarkBind project with the following file structure.

C:/mySite/
  ├── bookFiles/
  |      ├── book.md
  |      ├── chapter1.md
  |      └── chapter2.md
  └── reviewFiles/
         └── review.md

The book.md:

# My Book
<include src="chapter1.md" />
<include src="chapter2.md" />

The review.md:

# My Review
<include src="../bookFiles/book.md" />
...

The content of the chapter1.md and chapter2.md will be included in the review.md (via <include src="../bookFiles/book.md" />) although chapter1.md and chapter2.md are not in reviewFiles directory. i.e., <include src="chapter1.md" /> will be interpreted as <include src="c:/mySite/bookFiles/chapter1.md" />

In other words, <include> interprets the reused code relative to the original location of the file, not the location in which it is reused.


Specifying Variables in an <include>

It is possible to include variables in an <include>.

Example Specifying title and author variables in an <include> tag:

<include src="article.md">
  <variable name="title">My Title</variable>
  <variable name="author">John Doe</variable>
</include>

In article.md:

# {{ title }}<br>
Author: {{ author }}

These variables work the same way as variables in _markbind/variables.md, except that they only apply to the included file. They allow the included file to be reused as a template, for different source files using different variable values.

You can also specify include variables within the <include> tag itself by adding a var- prefix.

Example Specifying title and author variables inline:

<include src="article.md" var-title="My Title" var-author="John Doe" />

If the same variable is defined in a chain of <include>s (e.g. a.md includes b.md includes c.md...), variables defined in the top-most <include> will take precedence. Global variables (_markbind/variables.md) will take precedence over any <include> variables.

Using Boilerplate Files

If you find duplicating a code that needs to stay relative to the directory in which it usedboilerplate code fragment in multiple places of your code base, you can use a boilerplate file to avoid such duplication. Note that you cannot use a normal <include> in this case because the code included using a normal <include> stays relative to the original location while boilerplate code needs to be interpreted relative to the location it is being used.

Example Suppose you have a MarkBind project with the following file structure.

C:/mySite/
  ├── chapter1/
  |      ├── chapter.md
  |      ├── text.md
  |      └── exercises.md
  ├── chapter2/
  |      ├── chapter.md
  |      ├── text.md
  |      └── exercises.md
  └── book.md

The book.md:

# My Book
<include src="chapter1/chapter.md" />
<include src="chapter2/chapter.md" />

The chapter1/chapter.md:

## Text
<include src="text.md" />
## Exercises
<include src="exercises.md" />

The chapter2/chapter.md:

## Text
<include src="text.md" />
## Exercises
<include src="exercises.md" />

As you can see, both chapter.md files are exactly the same. If we were to use only one of the chapter.md files and <include> it twice in the book.md, we'll end up with the same chapter content duplicated twice, which is not what we want. In other words, chapter.md contains boilerplate code that needs to be interpreted relative to where it is applied, once relative to chapter1 directory and once relative to chapter2 directory.

To use a code fragment as a boilerplate file,

  1. Put the code in a file inside the _markbind/boilerplates directory.
  2. <include> the file as if a copy of it exists in any directory you want it to applied, but add the boilerplate attribute to the <include> tag.

Example Here's how you can use a boilerplate file to avoid duplicating the chapter.md:

C:/mySite/
  ├── _markbind/boilerplates/
  |      └── chapter.md
  ├── chapter1/
  |      ├── text.md
  |      └── exercises.md
  ├── chapter2/
  |      ├── text.md
  |      └── exercises.md
  └── book.md

The book.md:

# My Book
<include src="chapter1/chapter.md" boilerplate />
<include src="chapter2/chapter.md" boilerplate />

The _markbind/boilerplates/chapter.md:

## Text
<include src="text.md" />
## Exercises
<include src="exercises.md" />

Consider the line <include src="chapter1/chapter.md" boilerplate />. Note how you can use src="chapter1/chapter.md" there is no such file. MarkBind will use the chapter.md file /_markbind/boilerplates/ but interpret it as if the file exist in chapter1 directory (i.e., interpret the chapter1.md code relative to the chapter1 directory.

Similarly, <include src="chapter2/chapter.md" boilerplate /> interprets the chapter.md relative to the chapter2 directory.

If you have many boilerplate files, you can organize them into directories inside the _markbind directory. When using such boilerplate files, you need to replace boilerplate attribute with boilerplate="<path to file relative to _markbind/boilerplates>".

Example Suppose the chapter.md is places in a book directory:

C:/mySite/
  └── _markbind/boilerplates/
         └── book/
               └── chapter.md

It needs to be used as follows:

<include src="chapter1/chapter.md" boilerplate="book/chapter.md" />
<include src="chapter2/chapter.md" boilerplate="book/chapter.md" />
<include src="foo.md#bar" boilerplate inline trim>
  <variable name="x">5</variable>
</include>

Reusing Contents Across Sites

MarkBind supports reusing across sites. It allows you to include the pages you want from a sub-site in another main-site without having to change anything in the source files of the sub-site as long as the sub-site source files are inside the directory of the main site.

Example Suppose you have a site textbook and you want to include some pages from it in another site course. Given below is how you can locate the sub-site textbook inside the root directory of the main-site course so that files from textbook can be reused in the course site.

C:/course/
  ├── textbook/
  |      ├── index.md
  |      ├── overview.md
  |      └── site.json
  ├── index.md
  ├── reading.md
  └── site.json

reading.md (note how it reuses content from the sub-site textbook):

# Week 1 Reading:
<include src="textbook/overview.md" />

If you are using Git for version control, you can set up the sub-site repository as a Git sub-module of the main site repository.


Creating Content Variations

MarkBind can create sites that give more control to the reader. Given below are some mechanisms authors can use to create variations of content that gives more control to the reader in charting their own path through the content.

Allowing users to remove some contents

When the readers can remove an item from a page, they can create their own version of the page by removing items they don't want to see. This is especially useful when printing a page.

To make an element closeable, use v-closeable.

<div v-closeable>

Optional video:

@[youtube](v40b3ExbM0c)

</div>

This is how the content will appear. Note how you can hover over the content to access the ❌ button that can collapse the content.

Optional video:

Giving alternative contents

You can use a Tabs component to give alternative versions of content, for example, giving a code snippet in different programming languages.

Giving access to additional contents

You can use following components to give readers an option to access additional content at their discretion.

Organizing contents in alternative ways

You can take advantage of MarkBinds feature for content reuse, you can organize content in alternative ways to cater for different readers, without having to duplicate content. For example, you can have different pages that organizes the same information alphabetically, chronologically, by difficulty, group information by topic, etc.

Optimizing the Print View

To hide minimized panels in the print view, add the following code to a CSS file used in your site.

@media print {
    .card-container > .morph {
        display: none;
    }
}

Hiding some info in the generated content

To permanently hide a fragment from the reader:

<span class="d-none">
  content to hide ...
</span>

<panel header="..." add-class="d-none">
  content to hide ...
<panel>

To hide a fragment in one specific page, 'mark' the elements using a class:

<span class="extra">
  content to hide ...
</span>

Then, in a page-specific CSS file,

.extra {
  display: none; /* 'block' or 'inline-block' if you want it to show */
}

Creating slight variations of content

Tags are a good way to create multiple variations of a page within the same source file, such as to filter content for creating multiple different versions of the same page. See User Guide: Tweaking the Page Structure → Tags section for more information.