diff --git a/docs/userGuide/reusingContents.md b/docs/userGuide/reusingContents.md index fe7c61a965..d9fad356fe 100644 --- a/docs/userGuide/reusingContents.md +++ b/docs/userGuide/reusingContents.md @@ -157,6 +157,20 @@ You must use the `safe` filter when using such variables: {{ right_hand_2 }} {{ icon_arrow_right }} {{glyphicon_hand_right}} +### 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 `` tag. + +
+ +{{ icon_example }} Declaring page variables:
+ +`John Doe`
+My name is {{ full_name }}. This is {{ full_name }}'s site. +
+ +Note: These variables will also be applied to [`` 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. +
## The `include` tag diff --git a/src/lib/markbind/src/parser.js b/src/lib/markbind/src/parser.js index 2635d2472f..517c720dac 100644 --- a/src/lib/markbind/src/parser.js +++ b/src/lib/markbind/src/parser.js @@ -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) => { @@ -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); }; @@ -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; @@ -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)); } @@ -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 @@ -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'; diff --git a/test/functional/test_site/_markbind/variables.md b/test/functional/test_site/_markbind/variables.md index da1cb897c8..77be110efc 100644 --- a/test/functional/test_site/_markbind/variables.md +++ b/test/functional/test_site/_markbind/variables.md @@ -8,5 +8,6 @@ {{reference_level_2}} {{reference_level_3}} -Global variable overriding included variable -Global variable +Global Variable Overriding Included Variable +Global Variable +Global Variable Overriding Page Variable diff --git a/test/functional/test_site/expected/index.html b/test/functional/test_site/expected/index.html index 21af6137f0..48b201c9a0 100644 --- a/test/functional/test_site/expected/index.html +++ b/test/functional/test_site/expected/index.html @@ -42,6 +42,17 @@ Testing Page Navigation