From e521f97abad4097729ae286c0c379f7f9b68fa3c Mon Sep 17 00:00:00 2001 From: Daryl Tan <3646725+openorclose@users.noreply.github.com> Date: Sat, 7 Mar 2020 09:52:21 +0800 Subject: [PATCH] Allow changing parameter properties (#1075) --- .eslintrc.js | 1 + src/lib/markbind/src/parser.js | 142 +++++------ .../markbind/src/parsers/componentParser.js | 238 +++++++++--------- 3 files changed, 180 insertions(+), 201 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index e5049bf1bf..b7a079c568 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -29,6 +29,7 @@ module.exports = { "lodash/prefer-lodash-method": [0], "lodash/prefer-noop": [0], "max-len": ["error", { "code": 110 }], + "no-param-reassign": ["error", { "props": false }], "operator-linebreak": ["error", "before"], // override airbnb-base dev dependencies, latest version does not white list __mocks__ "import/no-extraneous-dependencies": [ diff --git a/src/lib/markbind/src/parser.js b/src/lib/markbind/src/parser.js index 7ba665129d..fa4d061776 100644 --- a/src/lib/markbind/src/parser.js +++ b/src/lib/markbind/src/parser.js @@ -126,22 +126,22 @@ class Parser { return _.clone(this.missingIncludeSrc); } - _renderIncludeFile(filePath, element, context, config, asIfAt = filePath) { + _renderIncludeFile(filePath, node, context, config, asIfAt = filePath) { try { this._fileCache[filePath] = this._fileCache[filePath] ? this._fileCache[filePath] : fs.readFileSync(filePath, 'utf8'); } catch (e) { // Read file fail - const missingReferenceErrorMessage = `Missing reference in: ${element.attribs[ATTRIB_CWF]}`; + const missingReferenceErrorMessage = `Missing reference in: ${node.attribs[ATTRIB_CWF]}`; e.message += `\n${missingReferenceErrorMessage}`; this._onError(e); - return utils.createErrorNode(element, e); + return utils.createErrorNode(node, e); } const fileContent = this._fileCache[filePath]; // cache the file contents to save some I/O const { parent, relative } = urlUtils.calculateNewBaseUrls(asIfAt, config.rootPath, config.baseUrlMap); const userDefinedVariables = config.userDefinedVariablesMap[path.resolve(parent, relative)]; // Extract included variables from the PARENT file - const includeVariables = Parser.extractIncludeVariables(element, context.variables); + const includeVariables = Parser.extractIncludeVariables(node, context.variables); // Extract page variables from the CHILD file const pageVariables = this.extractPageVariables(asIfAt, fileContent, userDefinedVariables, includeVariables); @@ -162,22 +162,22 @@ class Parser { }); const aliases = new Map(); Parser.FILE_ALIASES.set(cwf, aliases); - $('import[from]').each((index, element) => { - const filePath = path.resolve(path.dirname(cwf), element.attribs.from); - const variableNames = Object.keys(element.attribs) + $('import[from]').each((index, node) => { + const filePath = path.resolve(path.dirname(cwf), node.attribs.from); + const variableNames = Object.keys(node.attribs) .filter(name => name !== 'from' && name !== 'as'); // If no namespace is provided, we use the smallest name as one const largestName = variableNames.sort()[0]; // ... and prepend it with $__MARKBIND__ to reduce collisions. const generatedAlias = IMPORTED_VARIABLE_PREFIX + largestName; - const alias = _.hasIn(element.attribs, 'as') - ? element.attribs.as + const alias = _.hasIn(node.attribs, 'as') + ? node.attribs.as : generatedAlias; aliases.set(alias, filePath); this.staticIncludeSrc.push({ from: context.cwf, to: filePath }); // Render inner file content const { content: renderedContent, childContext, userDefinedVariables } - = this._renderIncludeFile(filePath, element, context, config); + = this._renderIncludeFile(filePath, node, context, config); this.extractInnerVariablesIfNotProcessed(renderedContent, childContext, config, filePath); const innerVariables = this.getImportedVariableMap(filePath); Parser.VARIABLE_LOOKUP.get(filePath).forEach((value, variableName, map) => { @@ -194,17 +194,23 @@ class Parser { } processDynamicResources(context, html) { - const self = this; const $ = cheerio.load(html, { xmlMode: false, decodeEntities: false, }); + + const { rootPath } = this; + function getAbsoluteResourcePath(elem, relativeResourcePath) { + const firstParent = elem.closest('div[data-included-from], span[data-included-from]'); + const originalSrc = utils.ensurePosix(firstParent.attr('data-included-from') || context); + const originalSrcFolder = path.posix.dirname(originalSrc); + const fullResourcePath = path.posix.join(originalSrcFolder, relativeResourcePath); + const resolvedResourcePath = path.posix.relative(utils.ensurePosix(rootPath), fullResourcePath); + return path.posix.join('{{hostBaseUrl}}', resolvedResourcePath); + } + $('img, pic, thumbnail').each(function () { const elem = $(this); - if (elem[0].name === 'thumbnail' && elem.attr('src') === undefined) { - // Thumbnail tag without src - return; - } const resourcePath = utils.ensurePosix(elem.attr('src')); if (resourcePath === undefined || resourcePath === '') { // Found empty img/pic resource in resourcePath @@ -214,12 +220,7 @@ class Parser { // Do not rewrite. return; } - const firstParent = elem.closest('div[data-included-from], span[data-included-from]'); - const originalSrc = utils.ensurePosix(firstParent.attr('data-included-from') || context); - const originalSrcFolder = path.posix.dirname(originalSrc); - const fullResourcePath = path.posix.join(originalSrcFolder, resourcePath); - const resolvedResourcePath = path.posix.relative(utils.ensurePosix(self.rootPath), fullResourcePath); - const absoluteResourcePath = path.posix.join('{{hostBaseUrl}}', resolvedResourcePath); + const absoluteResourcePath = getAbsoluteResourcePath(elem, resourcePath); $(this).attr('src', absoluteResourcePath); }); $('a, link').each(function () { @@ -233,12 +234,7 @@ class Parser { // Do not rewrite. return; } - const firstParent = elem.closest('div[data-included-from], span[data-included-from]'); - const originalSrc = utils.ensurePosix(firstParent.attr('data-included-from') || context); - const originalSrcFolder = path.posix.dirname(originalSrc); - const fullResourcePath = path.posix.join(originalSrcFolder, resourcePath); - const resolvedResourcePath = path.posix.relative(utils.ensurePosix(self.rootPath), fullResourcePath); - const absoluteResourcePath = path.posix.join('{{hostBaseUrl}}', resolvedResourcePath); + const absoluteResourcePath = getAbsoluteResourcePath(elem, resourcePath); $(this).attr('href', absoluteResourcePath); }); return $.html(); @@ -256,20 +252,18 @@ class Parser { } _parse(node, context, config) { - const element = node; - const self = this; - if (_.isArray(element)) { - return element.map(el => self._parse(el, context, config)); + if (_.isArray(node)) { + return node.map(el => this._parse(el, context, config)); } - if (Parser.isText(element)) { - return element; + if (Parser.isText(node)) { + return node; } - if (element.name) { - element.name = element.name.toLowerCase(); + if (node.name) { + node.name = node.name.toLowerCase(); } - if ((/^h[1-6]$/).test(element.name) && !element.attribs.id) { - const textContent = utils.getTextContent(element); + if ((/^h[1-6]$/).test(node.name) && !node.attribs.id) { + const textContent = utils.getTextContent(node); const slugifiedHeading = slugify(textContent, { decamelize: false }); let headerId = slugifiedHeading; @@ -281,59 +275,58 @@ class Parser { headerIdMap[slugifiedHeading] = 2; } - element.attribs.id = headerId; + node.attribs.id = headerId; } - switch (element.name) { + switch (node.name) { case 'md': - element.name = 'span'; + node.name = 'span'; cheerio.prototype.options.xmlMode = false; - element.children = cheerio.parseHTML(md.renderInline(cheerio.html(element.children)), true); + node.children = cheerio.parseHTML(md.renderInline(cheerio.html(node.children)), true); cheerio.prototype.options.xmlMode = true; break; case 'markdown': - element.name = 'div'; + node.name = 'div'; cheerio.prototype.options.xmlMode = false; - element.children = cheerio.parseHTML(md.render(cheerio.html(element.children)), true); + node.children = cheerio.parseHTML(md.render(cheerio.html(node.children)), true); cheerio.prototype.options.xmlMode = true; break; case 'panel': { - if (!_.hasIn(element.attribs, 'src')) { // dynamic panel + if (!_.hasIn(node.attribs, 'src')) { // dynamic panel break; } - const fileExists = utils.fileExists(element.attribs.src) + const fileExists = utils.fileExists(node.attribs.src) || utils.fileExists( urlUtils.calculateBoilerplateFilePath( - element.attribs.boilerplate, - element.attribs.src, config)); + node.attribs.boilerplate, + node.attribs.src, config)); if (fileExists) { - const { src, fragment } = element.attribs; + const { src, fragment } = node.attribs; const resultDir = path.dirname(path.join('{{hostBaseUrl}}', path.relative(config.rootPath, src))); const resultPath = path.join(resultDir, utils.setExtension(path.basename(src), '._include_.html')); - element.attribs.src = utils.ensurePosix(fragment ? `${resultPath}#${fragment}` : resultPath); + node.attribs.src = utils.ensurePosix(fragment ? `${resultPath}#${fragment}` : resultPath); } - delete element.attribs.boilerplate; + delete node.attribs.boilerplate; break; } default: break; } - componentParser.parseComponents(element, this._onError); + componentParser.parseComponents(node, this._onError); - if (element.children) { - element.children.forEach((child) => { - self._parse(child, context, config); + if (node.children) { + node.children.forEach((child) => { + this._parse(child, context, config); }); } - componentParser.postParseComponents(element, this._onError); + componentParser.postParseComponents(node, this._onError); - return element; + return node; } _trimNodes(node) { - const self = this; if (node.name === 'pre' || node.name === 'code') { return; } @@ -346,7 +339,7 @@ class Parser { node.children.splice(n, 1); n--; } else if (child.type === 'tag') { - self._trimNodes(child); + this._trimNodes(child); } } /* eslint-enable no-plusplus */ @@ -589,21 +582,20 @@ class Parser { } _rebaseReference(node, foundBase) { - const element = node; - if (_.isArray(element)) { - return element.map(el => this._rebaseReference(el, foundBase)); + if (_.isArray(node)) { + return node.map(el => this._rebaseReference(el, foundBase)); } - if (Parser.isText(element)) { - return element; + if (Parser.isText(node)) { + return node; } // Rebase children element const childrenBase = {}; - element.children.forEach((el) => { + node.children.forEach((el) => { this._rebaseReference(el, childrenBase); }); // rebase current element - if (element.attribs[ATTRIB_INCLUDE_PATH]) { - const filePath = element.attribs[ATTRIB_INCLUDE_PATH]; + if (node.attribs[ATTRIB_INCLUDE_PATH]) { + const filePath = node.attribs[ATTRIB_INCLUDE_PATH]; let newBaseUrl = urlUtils.calculateNewBaseUrls(filePath, this.rootPath, this.baseUrlMap); if (newBaseUrl) { const { relative, parent } = newBaseUrl; @@ -616,27 +608,27 @@ class Parser { if (bases.length !== 0) { // need to rebase newBaseUrl = combinedBases[bases[0]]; - if (element.children) { + if (node.children) { // ATTRIB_CWF is where the element was preprocessed - const currentBase = urlUtils.calculateNewBaseUrls(element.attribs[ATTRIB_CWF], + const currentBase = urlUtils.calculateNewBaseUrls(node.attribs[ATTRIB_CWF], this.rootPath, this.baseUrlMap); if (currentBase && currentBase.relative !== newBaseUrl) { cheerio.prototype.options.xmlMode = false; - const rendered = nunjucks.renderString(cheerio.html(element.children), { + const rendered = nunjucks.renderString(cheerio.html(node.children), { // This is to prevent the nunjuck call from converting {{hostBaseUrl}} to an empty string // and let the hostBaseUrl value be injected later. hostBaseUrl: '{{hostBaseUrl}}', baseUrl: `{{hostBaseUrl}}/${newBaseUrl}`, }, { path: filePath }); - element.children = cheerio.parseHTML(rendered, true); + node.children = cheerio.parseHTML(rendered, true); cheerio.prototype.options.xmlMode = true; } } } - delete element.attribs[ATTRIB_INCLUDE_PATH]; + delete node.attribs[ATTRIB_INCLUDE_PATH]; } - delete element.attribs[ATTRIB_CWF]; - return element; + delete node.attribs[ATTRIB_CWF]; + return node; } static resetVariables() { @@ -645,8 +637,8 @@ class Parser { Parser.PROCESSED_INNER_VARIABLES.clear(); } - static isText(element) { - return element.type === 'text' || element.type === 'comment'; + static isText(node) { + return node.type === 'text' || node.type === 'comment'; } /** diff --git a/src/lib/markbind/src/parsers/componentParser.js b/src/lib/markbind/src/parsers/componentParser.js index 3513c87fe6..7b7ef582cb 100644 --- a/src/lib/markbind/src/parsers/componentParser.js +++ b/src/lib/markbind/src/parsers/componentParser.js @@ -15,50 +15,48 @@ cheerio.prototype.options.decodeEntities = false; // Don't escape HTML entities /** * Parses the markdown attribute of the provided element, inserting the corresponding child * if there is no pre-existing slot child with the name of the attribute present. - * @param element Element to parse + * @param node Element to parse * @param attribute Attribute name to parse * @param isInline Whether to parse the attribute with only inline markdown-it rules * @param slotName Name attribute of the element to insert, which defaults to the attribute name */ -function _parseAttributeWithoutOverride(element, attribute, isInline, slotName = attribute) { - const el = element; +function _parseAttributeWithoutOverride(node, attribute, isInline, slotName = attribute) { + const hasAttributeSlot = node.children + && node.children.some(child => _.has(child.attribs, 'slot') && child.attribs.slot === slotName); - const hasAttributeSlot = el.children - && el.children.some(child => _.has(child.attribs, 'slot') && child.attribs.slot === slotName); - - if (!hasAttributeSlot && _.has(el.attribs, attribute)) { + if (!hasAttributeSlot && _.has(node.attribs, attribute)) { let rendered; if (isInline) { - rendered = vueAttrRenderer.renderInline(el.attribs[attribute]); + rendered = vueAttrRenderer.renderInline(node.attribs[attribute]); } else { - rendered = vueAttrRenderer.render(el.attribs[attribute]); + rendered = vueAttrRenderer.render(node.attribs[attribute]); } const attributeSlotElement = cheerio.parseHTML( ``, true); - el.children = el.children ? attributeSlotElement.concat(el.children) : attributeSlotElement; + node.children + = node.children ? attributeSlotElement.concat(node.children) : attributeSlotElement; } - delete el.attribs[attribute]; + delete node.attribs[attribute]; } /** * Takes an element, looks for direct elements with slots and transforms to avoid Vue parsing. * This is so that we can use bootstrap-vue popovers, tooltips, and modals. - * @param element Element to transform + * @param node Element to transform */ -function _transformSlottedComponents(element) { - element.children.forEach((child) => { - const c = child; - const slot = c.attribs && c.attribs.slot; +function _transformSlottedComponents(node) { + node.children.forEach((child) => { + const slot = child.attribs && child.attribs.slot; if (slot) { // Turns
... into
... - c.attribs['data-mb-html-for'] = slot; - delete c.attribs.slot; + child.attribs['data-mb-html-for'] = slot; + delete child.attribs.slot; } // similarly, need to transform templates to avoid Vue parsing - if (c.name === 'template') { - c.name = 'span'; + if (child.name === 'template') { + child.name = 'span'; } }); } @@ -67,22 +65,20 @@ function _transformSlottedComponents(element) { * Panels */ -function _parsePanelAttributes(element) { - const el = element; - - _parseAttributeWithoutOverride(element, 'alt', false, '_alt'); +function _parsePanelAttributes(node) { + _parseAttributeWithoutOverride(node, 'alt', false, '_alt'); - const slotChildren = el.children && el.children.filter(child => _.has(child.attribs, 'slot')); + const slotChildren = node.children && node.children.filter(child => _.has(child.attribs, 'slot')); const hasAltSlot = slotChildren && slotChildren.some(child => child.attribs.slot === '_alt'); const hasHeaderSlot = slotChildren && slotChildren.some(child => child.attribs.slot === 'header'); // If both are present, the header attribute has no effect, and we can simply remove it. if (hasAltSlot && hasHeaderSlot) { - delete el.attribs.header; + delete node.attribs.header; return; } - _parseAttributeWithoutOverride(element, 'header', false, '_header'); + _parseAttributeWithoutOverride(node, 'header', false, '_header'); } /** @@ -90,8 +86,8 @@ function _parsePanelAttributes(element) { * @param element Root element to search from * @returns {undefined|*} The header element, or undefined if none is found. */ -function _findHeaderElement(element) { - const elements = element.children; +function _findHeaderElement(node) { + const elements = node.children; if (!elements || !elements.length) { return undefined; } @@ -115,12 +111,10 @@ function _findHeaderElement(element) { * Assigns an id to the root element of a panel component using the heading specified in the * panel's header slot or attribute (if any), with the header slot having priority if present. * This is to ensure anchors still work when panels are in their minimized form. - * @param element The root panel element + * @param node The root panel element */ -function _assignPanelId(element) { - const el = element; - - const slotChildren = el.children && el.children.filter(child => _.has(child.attribs, 'slot')); +function _assignPanelId(node) { + const slotChildren = node.children && node.children.filter(child => _.has(child.attribs, 'slot')); const headerSlot = slotChildren.find(child => child.attribs.slot === 'header'); const headerAttributeSlot = slotChildren.find(child => child.attribs.slot === '_header'); @@ -136,7 +130,7 @@ function _assignPanelId(element) { + 'Please report this to the MarkBind developers. Thank you!'); } - el.attribs.id = header.attribs.id; + node.attribs.id = header.attribs.id; } } @@ -155,18 +149,17 @@ function _assignPanelId(element) { * For modals, we make it attempt to show the modal if it exists. */ -function _parseTrigger(element) { - const el = element; - el.name = 'span'; - const trigger = el.attribs.trigger || 'hover'; - const placement = el.attribs.placement || 'top'; - el.attribs[`v-b-popover.${trigger}.${placement}.html`] +function _parseTrigger(node) { + node.name = 'span'; + const trigger = node.attribs.trigger || 'hover'; + const placement = node.attribs.placement || 'top'; + node.attribs[`v-b-popover.${trigger}.${placement}.html`] = 'popoverGenerator'; - el.attribs[`v-b-tooltip.${trigger}.${placement}.html`] + node.attribs[`v-b-tooltip.${trigger}.${placement}.html`] = 'tooltipContentGetter'; const convertedTrigger = trigger === 'hover' ? 'mouseover' : trigger; - el.attribs[`v-on:${convertedTrigger}`] = `$refs['${el.attribs.for}'].show()`; - el.attribs.class = el.attribs.class ? `${el.attribs.class} trigger` : 'trigger'; + node.attribs[`v-on:${convertedTrigger}`] = `$refs['${node.attribs.for}'].show()`; + node.attribs.class = node.attribs.class ? `${node.attribs.class} trigger` : 'trigger'; } /* @@ -177,21 +170,20 @@ function _parseTrigger(element) { * Then, we add in a trigger for this popover. */ -function _parsePopover(element) { - const el = element; - _parseAttributeWithoutOverride(el, 'content', true); - _parseAttributeWithoutOverride(el, 'header', true); +function _parsePopover(node) { + _parseAttributeWithoutOverride(node, 'content', true); + _parseAttributeWithoutOverride(node, 'header', true); // TODO deprecate title attribute for popovers - _parseAttributeWithoutOverride(el, 'title', true, 'header'); + _parseAttributeWithoutOverride(node, 'title', true, 'header'); - el.name = 'span'; - const trigger = el.attribs.trigger || 'hover'; - const placement = el.attribs.placement || 'top'; - el.attribs['data-mb-component-type'] = 'popover'; - el.attribs[`v-b-popover.${trigger}.${placement}.html`] + node.name = 'span'; + const trigger = node.attribs.trigger || 'hover'; + const placement = node.attribs.placement || 'top'; + node.attribs['data-mb-component-type'] = 'popover'; + node.attribs[`v-b-popover.${trigger}.${placement}.html`] = 'popoverInnerGenerator'; - el.attribs.class = el.attribs.class ? `${el.attribs.class} trigger` : 'trigger'; - _transformSlottedComponents(el); + node.attribs.class = node.attribs.class ? `${node.attribs.class} trigger` : 'trigger'; + _transformSlottedComponents(node); } /* @@ -200,25 +192,22 @@ function _parsePopover(element) { * Similar to popovers. */ -function _parseTooltip(element) { - const el = element; - _parseAttributeWithoutOverride(el, 'content', true, '_content'); +function _parseTooltip(node) { + _parseAttributeWithoutOverride(node, 'content', true, '_content'); - el.name = 'span'; - const trigger = el.attribs.trigger || 'hover'; - const placement = el.attribs.placement || 'top'; - el.attribs['data-mb-component-type'] = 'tooltip'; - el.attribs[`v-b-tooltip.${trigger}.${placement}.html`] + node.name = 'span'; + const trigger = node.attribs.trigger || 'hover'; + const placement = node.attribs.placement || 'top'; + node.attribs['data-mb-component-type'] = 'tooltip'; + node.attribs[`v-b-tooltip.${trigger}.${placement}.html`] = 'tooltipInnerContentGetter'; - el.attribs.class = el.attribs.class ? `${el.attribs.class} trigger` : 'trigger'; - _transformSlottedComponents(el); + node.attribs.class = node.attribs.class ? `${node.attribs.class} trigger` : 'trigger'; + _transformSlottedComponents(node); } -function _renameSlot(element, originalName, newName) { - if (element.children) { - element.children.forEach((c) => { - const child = c; - +function _renameSlot(node, originalName, newName) { + if (node.children) { + node.children.forEach((child) => { if (_.has(child.attribs, 'slot') && child.attribs.slot === originalName) { child.attribs.slot = newName; } @@ -226,11 +215,10 @@ function _renameSlot(element, originalName, newName) { } } -function _renameAttribute(element, originalAttribute, newAttribute) { - const el = element; - if (_.has(el.attribs, originalAttribute)) { - el.attribs[newAttribute] = el.attribs[originalAttribute]; - delete el.attribs[originalAttribute]; +function _renameAttribute(node, originalAttribute, newAttribute) { + if (_.has(node.attribs, originalAttribute)) { + node.attribs[newAttribute] = node.attribs[originalAttribute]; + delete node.attribs[originalAttribute]; } } @@ -241,44 +229,43 @@ function _renameAttribute(element, originalAttribute, newAttribute) { * So, we will transform from markbind modal syntax into bootstrap-vue modal syntax. */ -function _parseModalAttributes(element) { - const el = element; - _parseAttributeWithoutOverride(el, 'header', true, 'modal-title'); +function _parseModalAttributes(node) { + _parseAttributeWithoutOverride(node, 'header', true, 'modal-title'); // TODO deprecate title attribute for modals - _parseAttributeWithoutOverride(el, 'title', true, 'modal-title'); + _parseAttributeWithoutOverride(node, 'title', true, 'modal-title'); // TODO deprecate modal-header, modal-footer attributes for modals - _renameSlot(el, 'header', 'modal-header'); - _renameSlot(el, 'footer', 'modal-footer'); + _renameSlot(node, 'header', 'modal-header'); + _renameSlot(node, 'footer', 'modal-footer'); - el.name = 'b-modal'; + node.name = 'b-modal'; - _renameAttribute(el, 'ok-text', 'ok-title'); - _renameAttribute(el, 'center', 'centered'); + _renameAttribute(node, 'ok-text', 'ok-title'); + _renameAttribute(node, 'center', 'centered'); - el.attribs['ok-only'] = ''; // only show OK button + node.attribs['ok-only'] = ''; // only show OK button - if (el.attribs.backdrop === 'false') { - el.attribs['no-close-on-backdrop'] = ''; + if (node.attribs.backdrop === 'false') { + node.attribs['no-close-on-backdrop'] = ''; } - delete el.attribs.backdrop; + delete node.attribs.backdrop; let size = ''; - if (_.has(el.attribs, 'large')) { + if (_.has(node.attribs, 'large')) { size = 'lg'; - delete el.attribs.large; - } else if (_.has(el.attribs, 'small')) { + delete node.attribs.large; + } else if (_.has(node.attribs, 'small')) { size = 'sm'; - delete el.attribs.small; + delete node.attribs.small; } - el.attribs.size = size; + node.attribs.size = size; // default for markbind is zoom, default for bootstrap-vue is fade - const effect = el.attribs.effect === 'fade' ? '' : 'mb-zoom'; - el.attribs['modal-class'] = effect; + const effect = node.attribs.effect === 'fade' ? '' : 'mb-zoom'; + node.attribs['modal-class'] = effect; - if (_.has(el.attribs, 'id')) { - el.attribs.ref = el.attribs.id; + if (_.has(node.attribs, 'id')) { + node.attribs.ref = node.attribs.id; } } @@ -286,20 +273,20 @@ function _parseModalAttributes(element) { * Tabs */ -function _parseTabAttributes(element) { - _parseAttributeWithoutOverride(element, 'header', true, '_header'); +function _parseTabAttributes(node) { + _parseAttributeWithoutOverride(node, 'header', true, '_header'); } /* * Tip boxes */ -function _parseBoxAttributes(element) { - _parseAttributeWithoutOverride(element, 'icon', true, '_icon'); - _parseAttributeWithoutOverride(element, 'header', false, '_header'); +function _parseBoxAttributes(node) { + _parseAttributeWithoutOverride(node, 'icon', true, '_icon'); + _parseAttributeWithoutOverride(node, 'header', false, '_header'); // TODO deprecate heading attribute for box - _parseAttributeWithoutOverride(element, 'heading', false, '_header'); + _parseAttributeWithoutOverride(node, 'heading', false, '_header'); // TODO warn when light and seamless attributes are both present } @@ -308,26 +295,25 @@ function _parseBoxAttributes(element) { * Dropdowns */ -function _parseDropdownAttributes(element) { - const el = element; - const slotChildren = el.children && el.children.filter(child => _.has(child.attribs, 'slot')); +function _parseDropdownAttributes(node) { + const slotChildren = node.children && node.children.filter(child => _.has(child.attribs, 'slot')); const hasHeaderSlot = slotChildren && slotChildren.some(child => child.attribs.slot === 'header'); // If header slot is present, the header attribute has no effect, and we can simply remove it. if (hasHeaderSlot) { - delete el.attribs.header; + delete node.attribs.header; // TODO deprecate text attribute of dropdown - delete el.attribs.text; + delete node.attribs.text; return; } // header attribute takes priority over text attribute - if (_.has(element.attribs, 'header')) { - _parseAttributeWithoutOverride(element, 'header', true, '_header'); - delete el.attribs.text; + if (_.has(node.attribs, 'header')) { + _parseAttributeWithoutOverride(node, 'header', true, '_header'); + delete node.attribs.text; } else { // TODO deprecate text attribute of dropdown - _parseAttributeWithoutOverride(element, 'text', true, '_header'); + _parseAttributeWithoutOverride(node, 'text', true, '_header'); } } @@ -335,33 +321,33 @@ function _parseDropdownAttributes(element) { * API */ -function parseComponents(element, errorHandler) { +function parseComponents(node, errorHandler) { try { - switch (element.name) { + switch (node.name) { case 'panel': - _parsePanelAttributes(element); + _parsePanelAttributes(node); break; case 'trigger': - _parseTrigger(element); + _parseTrigger(node); break; case 'popover': - _parsePopover(element); + _parsePopover(node); break; case 'tooltip': - _parseTooltip(element); + _parseTooltip(node); break; case 'modal': - _parseModalAttributes(element); + _parseModalAttributes(node); break; case 'tab': case 'tab-group': - _parseTabAttributes(element); + _parseTabAttributes(node); break; case 'box': - _parseBoxAttributes(element); + _parseBoxAttributes(node); break; case 'dropdown': - _parseDropdownAttributes(element); + _parseDropdownAttributes(node); break; default: break; @@ -376,11 +362,11 @@ function parseComponents(element, errorHandler) { } } -function postParseComponents(element, errorHandler) { +function postParseComponents(node, errorHandler) { try { - switch (element.name) { + switch (node.name) { case 'panel': - _assignPanelId(element); + _assignPanelId(node); break; default: break;