Skip to content

Commit

Permalink
Implement page variable functionality (#627)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamos-tay authored and yamgent committed Feb 4, 2019
1 parent 02c31a7 commit 6e2ea26
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 14 deletions.
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 @@ -89,9 +89,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 @@ -112,6 +112,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 @@ -230,10 +257,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 @@ -293,7 +325,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 @@ -304,6 +336,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 @@ -442,7 +476,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 }}

0 comments on commit 6e2ea26

Please sign in to comment.