Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/userGuide/reusingContents.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ As mentioned in _User Guide: MarkBind Syntax_, you can use built-in variables to
<p/>


##### Variables: Defaults

You can specify a default value for a variable, which is displayed when the variable is not specified in `variables.md` and by any of the [includes]({{ baseUrl }}/userGuide/reusingContents.html#the-include-tag) of the page. This is done by adding `or defaultValue` within the curly braces.

<div class="indented">

{{ icon_example }} If `name` is not declared in `variables.md`:<br>
<code>My name is {<span></span>{ name or "Anonymous" }}.</code> {{ icon_arrow_right }} My name is Anonymous.
</div>

##### Variables: Tips and Tricks

**Variables can refer to other variables** that are declared earlier, including built-in variables.
Expand Down Expand Up @@ -259,6 +269,33 @@ In other words, **`<include>` interprets the reused code relative to the origina

<hr><!-- ======================================================================================================= -->

##### Specifying Variables in an `<include>`

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

<div class="indented">

{{ icon_example }} Specifying `title` and `author` variables in an `<include>` tag:

```html
<include src="article.md">
<span id="title">My Title</span>
<span id="author">John Doe</span>
</include>
```

In `article.md`:

<code>
# {<span></span>{ title }}<br>
Author: {<span></span>{ author }}
</code>
Comment thread
jamos-tay marked this conversation as resolved.
</div>

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.

Comment thread
jamos-tay marked this conversation as resolved.
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 <tooltip content="code that needs to stay relative to the directory in which it used">_boilerplate code_</tooltip> 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.
Expand Down
33 changes: 32 additions & 1 deletion src/lib/markbind/src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,32 @@ function Parser(options) {
this.missingIncludeSrc = [];
}

/**
* Extract variables from an include element
* @param includeElement include element to extract variables from
* @param contextVariables local variables defined by parent pages
*/
function extractVariables(includeElement, contextVariables) {
const includedVariables = { ...contextVariables };
if (includeElement.children) {
includeElement.children.forEach((child) => {
if (child.name !== 'span') {
return;
}
if (!child.attribs.id) {
// eslint-disable-next-line no-console
console.warn(`Missing reference in ${includeElement.attribs[ATTRIB_CWF]}\n`
+ `Missing 'id' in variable for ${includeElement.attribs.src} include.`);
return;
}
if (!includedVariables[child.attribs.id]) {
includedVariables[child.attribs.id] = cheerio.html(child.children);
}
});
}
return includedVariables;
}

Parser.prototype.getDynamicIncludeSrc = function () {
return _.clone(this.dynamicIncludeSrc);
};
Expand Down Expand Up @@ -205,7 +231,11 @@ Parser.prototype._preprocess = function (node, context, config) {
let fileContent = self._fileCache[actualFilePath]; // cache the file contents to save some I/O
const { parent, relative } = calculateNewBaseUrls(filePath, config.rootPath, config.baseUrlMap);
const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)];
fileContent = nunjucks.renderString(fileContent, userDefinedVariables);

// process variables declared within the include
const includedVariables = extractVariables(element, context.includedVariables);

fileContent = nunjucks.renderString(fileContent, { ...includedVariables, ...userDefinedVariables });
delete element.attribs.boilerplate;
delete element.attribs.src;
delete element.attribs.inline;
Expand Down Expand Up @@ -265,6 +295,7 @@ Parser.prototype._preprocess = function (node, context, config) {
const childContext = _.cloneDeep(context);
childContext.cwf = filePath;
childContext.source = isIncludeSrcMd ? 'md' : 'html';
childContext.includedVariables = includedVariables;
if (element.children && element.children.length > 0) {
element.children = element.children.map(e => self._preprocess(e, childContext, config));
}
Expand Down
3 changes: 3 additions & 0 deletions test/test_site/_markbind/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
<span id="reference_level_2">{{reference_level_1}}</span>
<span id="reference_level_3">{{reference_level_2}}</span>
<span id="reference_level_4">{{reference_level_3}}</span>

<span id="global_variable_overriding_included_variable">Global variable overriding included variable</span>
<span id="included_global_variable">Global variable</span>
45 changes: 45 additions & 0 deletions test/test_site/expected/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@
<nav class="nav nav-pills flex-column my-0" style="margin-left: 5%; flex-wrap: nowrap;">
<a class="nav-link py-1" href="#fragment-with-leading-spaces-and-newline">Fragment with leading spaces and newline&#x200E;</a>
</nav>
<a class="nav-link py-1" href="#include-with-custom-variables">Include with custom variables&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable">Test included variable&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable-with-markdown">Test included variable with markdown&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable-as-attribute">Test included variable as attribute&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable-as-html-element">Test included variable as html element&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable-overridden-by-variables-md">Test included variable overridden by variables.md&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variables-in-included-file">Test included variables in included file&#x200E;</a>
<a class="nav-link py-1" href="#inner-included-variables-should-not-leak-into-other-files">Inner included variables should not leak into other files&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable-with-global-variable">Test included variable with global variable&#x200E;</a>
<a class="nav-link py-1" href="#test-included-variable-overridden-by-set">Test included variable overridden by set&#x200E;</a>
<a class="nav-link py-1" href="#test-missing-variable-with-default">Test missing variable with default&#x200E;</a>
<a class="nav-link py-1" href="#included-variables-should-not-leak-into-other-files">Included variables should not leak into other files&#x200E;</a>
<a class="nav-link py-1" href="#panel-without-src">Panel without src&#x200E;</a>
<nav class="nav nav-pills flex-column my-0" style="margin-left: 5%; flex-wrap: nowrap;">
<a class="nav-link py-1" href="#panel-without-src-header">Panel without src header&#x200E;</a>
Expand Down Expand Up @@ -343,6 +355,39 @@ <h2 id="feature-list">Feature list<a class="fa fa-anchor" href="#feature-list"><
<img src="/test_site/sub_site/images/I'm not allowed to use my favorite tool.png"></div>
<h1 id="trimmed-include">Trimmed include<a class="fa fa-anchor" href="#trimmed-include"></a></h1>
<h2 id="fragment-with-leading-spaces-and-newline"><span>Fragment with leading spaces and newline</span><a class="fa fa-anchor" href="#fragment-with-leading-spaces-and-newline"></a></h2>
<h1 id="include-with-custom-variables">Include with custom variables<a class="fa fa-anchor" href="#include-with-custom-variables"></a></h1>
<div>
<h1 id="test-included-variable">Test included variable<a class="fa fa-anchor" href="#test-included-variable"></a></h1>
<p>Included variable</p>
<h1 id="test-included-variable-with-markdown">Test included variable with markdown<a class="fa fa-anchor" href="#test-included-variable-with-markdown"></a></h1>
<p><strong><strong>Included variable with markdown</strong></strong>
</p>
<h1 id="test-included-variable-as-attribute">Test included variable as attribute<a class="fa fa-anchor" href="#test-included-variable-as-attribute"></a></h1>
<p style="color: blue">Test</p>
<h1 id="test-included-variable-as-html-element">Test included variable as html element<a class="fa fa-anchor" href="#test-included-variable-as-html-element"></a></h1>
<p><span>Included variable within html element</span></p>
<h1 id="test-included-variable-overridden-by-variables-md">Test included variable overridden by <a href="http://variables.md">variables.md</a><a class="fa fa-anchor" href="#test-included-variable-overridden-by-variables-md"></a></h1>
<p>Global variable overriding included variable</p>
<h1 id="test-included-variables-in-included-file">Test included variables in included file<a class="fa fa-anchor" href="#test-included-variables-in-included-file"></a></h1>
<div>
<p>Included variable in outer included file</p>
<p>Included variable overriding inner variable</p>
</div>
<h1 id="inner-included-variables-should-not-leak-into-other-files">Inner included variables should not leak into other files<a class="fa fa-anchor" href="#inner-included-variables-should-not-leak-into-other-files"></a></h1>
<div>
<p>Should be blank:</p>
</div>
<h1 id="test-included-variable-with-global-variable">Test included variable with global variable<a class="fa fa-anchor" href="#test-included-variable-with-global-variable"></a></h1>
<p>Included variable with Global variable</p>
<h1 id="test-included-variable-overridden-by-set">Test included variable overridden by set<a class="fa fa-anchor" href="#test-included-variable-overridden-by-set"></a></h1>
<p>Inner variable overridden by set Global variable overridden by set</p>
<h1 id="test-missing-variable-with-default">Test missing variable with default<a class="fa fa-anchor" href="#test-missing-variable-with-default"></a></h1>
<p>Missing Variable</p>
</div>
<h1 id="included-variables-should-not-leak-into-other-files">Included variables should not leak into other files<a class="fa fa-anchor" href="#included-variables-should-not-leak-into-other-files"></a></h1>
<div>
<p>Should be blank:</p>
</div>
<h1 id="panel-without-src">Panel without src<a class="fa fa-anchor" href="#panel-without-src"></a></h1>
<panel header="## Panel without src header<a class='fa fa-anchor' href='#panel-without-src-header'></a>" expanded="">
<div>
Expand Down
12 changes: 12 additions & 0 deletions test/test_site/expected/siteData.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@
"include-from-another-markbind-site": "Include from another Markbind site",
"trimmed-include": "Trimmed include",
"fragment-with-leading-spaces-and-newline": "Fragment with leading spaces and newline",
"include-with-custom-variables": "Include with custom variables",
"test-included-variable": "Test included variable",
"test-included-variable-with-markdown": "Test included variable with markdown",
"test-included-variable-as-attribute": "Test included variable as attribute",
"test-included-variable-as-html-element": "Test included variable as html element",
"test-included-variable-overridden-by-variables-md": "Test included variable overridden by variables.md",
"test-included-variables-in-included-file": "Test included variables in included file",
"inner-included-variables-should-not-leak-into-other-files": "Inner included variables should not leak into other files",
"test-included-variable-with-global-variable": "Test included variable with global variable",
"test-included-variable-overridden-by-set": "Test included variable overridden by set",
"test-missing-variable-with-default": "Test missing variable with default",
"included-variables-should-not-leak-into-other-files": "Included variables should not leak into other files",
"panel-without-src": "Panel without src",
"panel-with-normal-src": "Panel with normal src",
"panel-with-src-from-a-page-segment": "Panel with src from a page segment",
Expand Down
18 changes: 18 additions & 0 deletions test/test_site/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,24 @@ head: myCustomHead.md, myCustomHead2.md

## <include src="testTrimInclude.md" trim inline />

# Include with custom variables

<include src="testIncludeVariables.md">
<span id="included_variable">Included variable</span>
<span id="included_variable_with_markdown">__**Included variable with markdown**__</span>
<span id="included_variable_as_attribute">color: blue</span>
<span id="included_variable_as_html_element"><span>Included variable within html element</span></span>
<span id="global_variable_overriding_included_variable">Included variable overridden by global variable</span>
<span id="included_variable_inner_overridden">Included variable overriding inner variable</span>
<span id="included_variable_in_outer_included_file">Included variable in outer included file</span>
<span id="included_variable_should_not_leak">Included variable should not leak into other files</span>
<span id="included_variable_with_global_variable">Included variable with {{ included_global_variable }}</span>
</include>

# Included variables should not leak into other files

<include src="testIncludeVariableLeak.md" />

# Panel without src
<panel header="## Panel without src header" expanded>
<markdown>
Expand Down
1 change: 1 addition & 0 deletions test/test_site/testIncludeVariableLeak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Should be blank: {{ included_variable_should_not_leak }}
1 change: 1 addition & 0 deletions test/test_site/testIncludeVariableLeakInner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Should be blank: {{ included_variable_should_not_leak_inner }}
36 changes: 36 additions & 0 deletions test/test_site/testIncludeVariables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Test included variable
{{ included_variable }}

# Test included variable with markdown
{{ included_variable_with_markdown }}

# Test included variable as attribute
<p style="{{ included_variable_as_attribute }}">Test</p>

# Test included variable as html element
{{ included_variable_as_html_element }}

# Test included variable overridden by variables.md
{{ global_variable_overriding_included_variable }}

# Test included variables in included file
<include src="testIncludeVariablesIncludedFile.md">
<span id="included_variable_inner_overridden">Included variable overridden by outer variable</span>
<span id="included_variable_should_not_leak_inner">Included variable should not leak into other files</span>
</include>

# Inner included variables should not leak into other files
<include src="testIncludeVariableLeakInner.md" />

# Test included variable with global variable
{{ included_variable_with_global_variable }}

{% set included_variable = "Inner variable overridden by set" %}
{% set included_global_variable = "Global variable overridden by set" %}

# Test included variable overridden by set
{{ included_variable }}
{{ included_global_variable }}

# Test missing variable with default
{{ missing_variable or "Missing Variable" }}
3 changes: 3 additions & 0 deletions test/test_site/testIncludeVariablesIncludedFile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{ included_variable_in_outer_included_file }}

{{ included_variable_inner_overridden }}