terriajs
Version:
Geospatial data visualization platform.
94 lines (80 loc) • 3.19 kB
JavaScript
;
const React = require('react');
const HtmlToReact = require('html-to-react');
const combine = require('terriajs-cesium/Source/Core/combine');
const defined = require('terriajs-cesium/Source/Core/defined');
const CustomComponents = require('./CustomComponents');
const htmlToReactParser = new HtmlToReact.Parser({
decodeEntities: true
});
const processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);
const isValidNode = function() {
return true;
};
const shouldProcessEveryNodeExceptWhiteSpace = function(node) {
// Use this to avoid white space between table elements, eg.
// <table> <tbody> <tr>\n<td>x</td> <td>3</td> </tr> </tbody> </table>
// being rendered as empty <span> elements, and causing React errors.
return node.type !== 'text' || node.data.trim();
};
let keyIndex = 0;
/**
* @private
*/
function getProcessingInstructions(context) {
/**
* @private
*/
function boundProcessor(processor) {
return {
shouldProcessNode: processor.shouldProcessNode,
processNode: processor.processNode.bind(null, context)
};
}
// Process custom nodes specially.
let processingInstructions = [];
const customComponents = CustomComponents.values();
for (let i = 0; i < customComponents.length; i++) {
const customComponent = customComponents[i];
processingInstructions.push({
shouldProcessNode: node => (node.name === customComponent.name),
processNode: customComponent.processNode.bind(null, context)
});
const processors = customComponent.furtherProcessing;
if (defined(processors)) {
processingInstructions = processingInstructions.concat(
processors.map(boundProcessor)
);
}
}
// Make sure any <a href> tags open in a new window
processingInstructions.push({
shouldProcessNode: node => node.name === 'a',
processNode: function(node, children) { // eslint-disable-line react/display-name
return React.createElement('a', combine({
key: 'anchor-' + (keyIndex++),
target: '_blank',
rel: 'noreferrer noopener'
}, node.attribs), node.data, children);
}
});
// Process all other nodes as normal.
processingInstructions.push({
shouldProcessNode: shouldProcessEveryNodeExceptWhiteSpace,
processNode: processNodeDefinitions.processDefaultNode
});
return processingInstructions;
}
/**
* Return html as a React Element.
* @param {String} html
* @param {Object} [context] Provide any further information that custom components need to know here, eg. which feature and catalogItem they come from.
* @return {ReactElement}
*/
function parseCustomHtmlToReact(html, context) {
if (!defined(html) || html.length === 0) {
return html;
}
return htmlToReactParser.parseWithInstructions(html, isValidNode, getProcessingInstructions(context || {}));
}
module.exports = parseCustomHtmlToReact;