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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 DownExpand 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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 }}