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
14 changes: 14 additions & 0 deletions docs/userGuide/reusingContents.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,20 @@ You must use the `safe` filter when using such variables:
<code>{<span></span>{ right_hand_2 }}</code> {{ icon_arrow_right }} {{glyphicon_hand_right}}
</div>

### Page Variables

**You can also declare variables for use within a single page.** These variables work exactly the same as regular variables, except that their values only apply to the page they are declared in. This can be done by using the `<variable>` tag.

<div class="indented">

{{ icon_example }} Declaring page variables:<br>

`<variable name="full_name">John Doe</variable>`<br>
<code>My name is {<span></span>{ full_name }}. This is {<span></span>{ full_name }}'s site.</code>
</div>

Note: These variables will also be applied to [`<include>` files]({{ baseUrl }}/userGuide/reusingContents.html#the-include-tag). If the same variable is defined in a chain of pages (e.g. `a.md` includes `b.md` includes `c.md`...), variables defined in the top-most page will take precedence. Global variables (`_markbind/variables.md`) will take precedence over any page variables.

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

## The `include` tag
Expand Down
50 changes: 43 additions & 7 deletions src/lib/markbind/src/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ function Parser(options) {
/**
* Extract variables from an include element
* @param includeElement include element to extract variables from
* @param contextVariables local variables defined by parent pages
* @param contextVariables variables defined by parent pages
*/
function extractVariables(includeElement, contextVariables) {
function extractIncludeVariables(includeElement, contextVariables) {
const includedVariables = { ...contextVariables };
if (includeElement.children) {
includeElement.children.forEach((child) => {
Expand All @@ -114,6 +114,33 @@ function extractVariables(includeElement, contextVariables) {
return includedVariables;
}

/**
* Extract page variables from a page
* @param filename for error printing
* @param data to extract variables from
* @param userDefinedVariables global variables
* @param contextVariables variables defined by parent pages
*/
function extractPageVariables(fileName, data, userDefinedVariables, contextVariables) {
const $ = cheerio.load(data);
const pageVariables = { ...contextVariables };
$('variable').each(function () {
const variableElement = $(this);
const variableName = variableElement.attr('name');
if (!variableName) {
// eslint-disable-next-line no-console
console.warn(`Missing 'name' for variable in ${fileName}\n`);
return;
}
if (!pageVariables[variableName]) {
pageVariables[variableName]
= nunjucks.renderString(md.renderInline(variableElement.html()),
{ ...pageVariables, ...userDefinedVariables });
}
});
return pageVariables;
}

Parser.prototype.getDynamicIncludeSrc = function () {
return _.clone(this.dynamicIncludeSrc);
};
Expand Down Expand Up @@ -232,10 +259,15 @@ Parser.prototype._preprocess = function (node, context, config) {
const { parent, relative } = calculateNewBaseUrls(filePath, config.rootPath, config.baseUrlMap);
const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)];

// process variables declared within the include
const includedVariables = extractVariables(element, context.includedVariables);
// Extract included variables from the PARENT file
let allVariables = extractIncludeVariables(element, context.variables);

// Extract page variables from the CHILD file
allVariables = extractPageVariables(element.attribs.src, fileContent, userDefinedVariables, allVariables);

// Render inner file content
fileContent = nunjucks.renderString(fileContent, { ...allVariables, ...userDefinedVariables });

fileContent = nunjucks.renderString(fileContent, { ...includedVariables, ...userDefinedVariables });
delete element.attribs.boilerplate;
delete element.attribs.src;
delete element.attribs.inline;
Expand Down Expand Up @@ -295,7 +327,7 @@ Parser.prototype._preprocess = function (node, context, config) {
const childContext = _.cloneDeep(context);
childContext.cwf = filePath;
childContext.source = isIncludeSrcMd ? 'md' : 'html';
childContext.includedVariables = includedVariables;
childContext.variables = allVariables;
if (element.children && element.children.length > 0) {
element.children = element.children.map(e => self._preprocess(e, childContext, config));
}
Expand All @@ -306,6 +338,8 @@ Parser.prototype._preprocess = function (node, context, config) {
element.attribs.src = filePath;
this.dynamicIncludeSrc.push({ from: context.cwf, to: actualFilePath, asIfTo: filePath });
return element;
} else if (element.name === 'variable') {
return createEmptyNode();
} else {
if (element.name === 'body') {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -444,7 +478,9 @@ Parser.prototype.includeFile = function (file, config) {
}
const { parent, relative } = calculateNewBaseUrls(file, config.rootPath, config.baseUrlMap);
const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)];
const fileContent = nunjucks.renderString(data, userDefinedVariables);
const pageVariables = extractPageVariables(path.basename(file), data, userDefinedVariables, {});
const fileContent = nunjucks.renderString(data, { ...pageVariables, ...userDefinedVariables });
context.variables = pageVariables;
const fileExt = utils.getExt(file);
if (utils.isMarkdownFileExt(fileExt)) {
context.source = 'md';
Expand Down
5 changes: 3 additions & 2 deletions test/functional/test_site/_markbind/variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<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>
<span id="global_variable_overriding_included_variable">Global Variable Overriding Included Variable</span>
<span id="global_variable">Global Variable</span>
<span id="page_global_variable_overriding_page_variable">Global Variable Overriding Page Variable</span>
50 changes: 48 additions & 2 deletions test/functional/test_site/expected/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@
<a class="navbar-brand" style="white-space: inherit; color: black" href="#">Testing Page Navigation</a>
<nav class="nav nav-pills flex-column my-0 small" style="flex-wrap: nowrap;">
<a class="nav-link py-1" href="#variables-that-reference-another-variable">Variables that reference another variable&#x200E;</a>
<a class="nav-link py-1" href="#page-variable">Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#page-variable-with-html-and-md">Page Variable with HTML and MD&#x200E;</a>
<a class="nav-link py-1" href="#nested-page-variable">Nested Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#page-variable-with-global-variable">Page Variable with Global Variable&#x200E;</a>
<a class="nav-link py-1" href="#page-variable-referencing-page-variable">Page Variable referencing Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#global-variable-overriding-page-variable">Global Variable overriding Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#test-page-variable-and-included-variable-integrations">Test Page Variable and Included Variable Integrations&#x200E;</a>
<a class="nav-link py-1" href="#outer-page-variable-overriding-inner-page-variable">Outer Page Variable Overriding Inner Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#included-variable-overriding-page-variable">Included Variable Overriding Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#page-variable-referencing-included-variable">Page Variable Referencing Included Variable&#x200E;</a>
<a class="nav-link py-1" href="#page-variable-referencing-outer-page-variable">Page Variable Referencing Outer Page Variable&#x200E;</a>
<a class="nav-link py-1" href="#heading-with-multiple-keywords">Heading with multiple keywords&#x200E;</a>
<a class="nav-link py-1" href="#heading-with-keyword-in-panel">Heading with keyword in panel&#x200E;</a>
<a class="nav-link py-1" href="#panel-with-heading-with-keyword">Panel with heading with keyword&#x200E;</a>
Expand Down Expand Up @@ -255,6 +266,41 @@ <h1 id="variables-that-reference-another-variable">Variables that reference anot
<p><span class="glyphicon glyphicon-education" aria-hidden="true"></span></p>
<p>This variable can be referenced.</p>
<p>References can be several levels deep.</p>
<h1 id="page-variable">Page Variable<a class="fa fa-anchor" href="#page-variable"></a></h1>
<div></div>
Page Variable
<h1 id="page-variable-with-html-and-md">Page Variable with HTML and MD<a class="fa fa-anchor" href="#page-variable-with-html-and-md"></a></h1>
<div></div>
Page Variable with <span style="color: blue;">HTML</span> and <strong>Markdown</strong>
<h1 id="nested-page-variable">Nested Page Variable<a class="fa fa-anchor" href="#nested-page-variable"></a></h1>
<div>
<span>
<div></div></span></div>
Nested Page Variable
<h1 id="page-variable-with-global-variable">Page Variable with Global Variable<a class="fa fa-anchor" href="#page-variable-with-global-variable"></a></h1>
<div></div>
Page Variable with Global Variable
<h1 id="page-variable-referencing-page-variable">Page Variable referencing Page Variable<a class="fa fa-anchor" href="#page-variable-referencing-page-variable"></a></h1>
<div></div>
Page Variable referencing Page Variable
<h1 id="global-variable-overriding-page-variable">Global Variable overriding Page Variable<a class="fa fa-anchor" href="#global-variable-overriding-page-variable"></a></h1>
<div></div>
Global Variable Overriding Page Variable
<h1 id="test-page-variable-and-included-variable-integrations">Test Page Variable and Included Variable Integrations<a class="fa fa-anchor" href="#test-page-variable-and-included-variable-integrations"></a></h1>
<div>
<h1 id="outer-page-variable-overriding-inner-page-variable">Outer Page Variable Overriding Inner Page Variable<a class="fa fa-anchor" href="#outer-page-variable-overriding-inner-page-variable"></a></h1>
<div></div>
Page Variable
<h1 id="included-variable-overriding-page-variable">Included Variable Overriding Page Variable<a class="fa fa-anchor" href="#included-variable-overriding-page-variable"></a></h1>
<div></div>
Included Variable Overriding Page Variable
<h1 id="page-variable-referencing-included-variable">Page Variable Referencing Included Variable<a class="fa fa-anchor" href="#page-variable-referencing-included-variable"></a></h1>
<div></div>
Page Variable Referencing Included Variable
<h1 id="page-variable-referencing-outer-page-variable">Page Variable Referencing Outer Page Variable<a class="fa fa-anchor" href="#page-variable-referencing-outer-page-variable"></a></h1>
<div></div>
Page Variable Referencing Outer Page Variable
</div>
<h1 id="heading-with-multiple-keywords">Heading with multiple keywords<a class="fa fa-anchor" href="#heading-with-multiple-keywords"></a></h1>
<p><span class="keyword">keyword 1</span>
<span class="keyword">keyword 2</span></p>
Expand Down Expand Up @@ -397,7 +443,7 @@ <h1 id="test-included-variable-as-attribute">Test included variable as attribute
<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>
<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>
Expand All @@ -408,7 +454,7 @@ <h1 id="inner-included-variables-should-not-leak-into-other-files">Inner include
<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>
<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>
Expand Down
11 changes: 11 additions & 0 deletions test/functional/test_site/expected/siteData.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@
"panel-content-of-outer-nested-panel": "Panel content of outer nested panel",
"feature-list": "Feature list",
"variables-that-reference-another-variable": "Variables that reference another variable",
"page-variable": "Page Variable",
"page-variable-with-html-and-md": "Page Variable with HTML and MD",
"nested-page-variable": "Nested Page Variable",
"page-variable-with-global-variable": "Page Variable with Global Variable",
"page-variable-referencing-page-variable": "Page Variable referencing Page Variable",
"global-variable-overriding-page-variable": "Global Variable overriding Page Variable",
"test-page-variable-and-included-variable-integrations": "Test Page Variable and Included Variable Integrations",
"outer-page-variable-overriding-inner-page-variable": "Outer Page Variable Overriding Inner Page Variable",
"included-variable-overriding-page-variable": "Included Variable Overriding Page Variable",
"page-variable-referencing-included-variable": "Page Variable Referencing Included Variable",
"page-variable-referencing-outer-page-variable": "Page Variable Referencing Outer Page Variable",
"heading-with-multiple-keywords": "Heading with multiple keywords | keyword 1, keyword 2",
"heading-with-keyword-in-panel": "Heading with keyword in panel | panel keyword",
"expanded-panel-without-heading-with-keyword": "Expanded panel without heading with keyword",
Expand Down
36 changes: 35 additions & 1 deletion test/functional/test_site/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,40 @@ head: myCustomHead.md, myCustomHead2.md

{{reference_level_4}}

# Page Variable
<variable name="page_variable">Page Variable</variable>
{{ page_variable }}

# Page Variable with HTML and MD
<variable name="page_variable_with_HTML_and_MD">Page Variable with <span style="color: blue;">HTML</span> and **Markdown**</variable>
{{ page_variable_with_HTML_and_MD }}

# Nested Page Variable
<div>
<span>
<variable name="nested_page_variable">Nested Page Variable</variable>
</span>
</div>
{{ nested_page_variable }}

# Page Variable with Global Variable
<variable name="page_variable_with_global_variable">Page Variable with {{ global_variable }}</variable>
{{ page_variable_with_global_variable }}

# Page Variable referencing Page Variable
<variable name="page_variable_referencing_page_variable">Page Variable referencing {{ page_variable }}</variable>
{{ page_variable_referencing_page_variable }}

# Global Variable overriding Page Variable
<variable name="page_global_variable_overriding_page_variable">Page Variable overridden by Global Variable</variable>
{{ page_global_variable_overriding_page_variable }}

# Test Page Variable and Included Variable Integrations
<include src="testPageVariablesInInclude.md">
<span id="included_variable">Included Variable</span>
<span id="included_variable_overriding_page_variable">Included Variable Overriding Page Variable</span>
</include>

# Heading with multiple keywords
<span class="keyword">keyword 1</span>
<span class="keyword">keyword 2</span>
Expand Down Expand Up @@ -108,7 +142,7 @@ head: myCustomHead.md, myCustomHead2.md
<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>
<span id="included_variable_with_global_variable">Included variable with {{ global_variable }}</span>
</include>

# Included variables should not leak into other files
Expand Down
4 changes: 2 additions & 2 deletions test/functional/test_site/testIncludeVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
{{ included_variable_with_global_variable }}

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

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

# Test missing variable with default
{{ missing_variable or "Missing Variable" }}
15 changes: 15 additions & 0 deletions test/functional/test_site/testPageVariablesInInclude.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Outer Page Variable Overriding Inner Page Variable
<variable name="page_variable">Inner Page Variable Overridden by Outer Page Variable</variable>
{{ page_variable }}

# Included Variable Overriding Page Variable
<variable name="included_variable_overriding_page_variable">Page Variable Overridden by Included Variable</variable>
{{ included_variable_overriding_page_variable }}

# Page Variable Referencing Included Variable
<variable name="page_variable_referencing_included_variable">Page Variable Referencing {{ included_variable }}</variable>
{{ page_variable_referencing_included_variable }}

# Page Variable Referencing Outer Page Variable
<variable name="page_variable_referencing_outer_page_variable">Page Variable Referencing Outer {{ page_variable }}</variable>
{{ page_variable_referencing_outer_page_variable }}