@mirrormedia/lilith-draft-renderer
Version:
## Introduction
121 lines (108 loc) • 4.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EmbeddedCodeBlock = exports.Caption = exports.Block = void 0;
var _react = _interopRequireWildcard(require("react"));
var _styledComponents = _interopRequireDefault(require("styled-components"));
var _nodeHtmlParser = require("node-html-parser");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const Block = _styledComponents.default.div`
position: relative;
white-space: normal;
/* styles for image link */
img.img-responsive {
margin: 0 auto;
max-width: 100%;
height: auto;
display: block;
}
`;
exports.Block = Block;
const Caption = _styledComponents.default.div`
line-height: 1.43;
letter-spacing: 0.4px;
${({
theme
}) => theme.fontSize.xs};
color: #808080;
padding: 15px 15px 0 15px;
`;
exports.Caption = Caption;
const EmbeddedCodeBlock = entity => {
const {
caption,
embeddedCode
} = entity.getData();
const embedded = (0, _react.useRef)(null); // `embeddedCode` is a string, which may includes
// multiple script tags and other html tags.
// Here we separate script tags and other html tags
// by using the isomorphic html parser 'node-html-parser'
// into scripts nodes and non-script nodes.
//
// For non-script nodes we simply put them into dangerouslySetInnerHtml.
//
// For scripts nodes we only append them on the client side. So we handle scripts
// nodes when useEffect is called.
// The reasons we don't insert script tags through dangerouslySetInnerHtml:
// 1. Since react use setInnerHtml to append the htmlStirng received from
// dangerouslySetInnerHtml, scripts won't be triggered.
// 2. Although the setInnerhtml way won't trigger script tags, those script tags
// will still show on the HTML provided from SSR. When the browser parse the
// html it will run those script and produce unexpected behavior.
const nodes = (0, _react.useMemo)(() => {
const ele = (0, _nodeHtmlParser.parse)(`<div id="draft-embed">${embeddedCode}</div>`);
const scripts = ele.querySelectorAll('script');
scripts.forEach(s => {
s.remove();
});
const nonScripts = ele.querySelectorAll('div#draft-embed > :not(script)');
const nonScriptsHtml = nonScripts.reduce((prev, next) => prev + next.toString(), '');
return {
scripts,
nonScripts,
nonScriptsHtml
};
}, [embeddedCode]);
const {
scripts,
nonScriptsHtml
} = nodes;
(0, _react.useEffect)(() => {
if (embedded.current) {
const node = embedded.current;
const fragment = document.createDocumentFragment();
scripts.forEach(s => {
const scriptEle = document.createElement('script');
const attrs = s.attributes;
for (const key in attrs) {
scriptEle.setAttribute(key, attrs[key]);
}
scriptEle.text = s.text || '';
fragment.appendChild(scriptEle);
});
node.appendChild(fragment);
}
}, [scripts]);
const shouldShowCaption = caption && caption !== 'reporter-scroll-video';
return (
/*#__PURE__*/
// only for READr
// if `caption === 'reporter-scroll-video'`,embeddedCode need to cover header
_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("input", {
hidden: true,
disabled: true
}), /*#__PURE__*/_react.default.createElement(Block, {
style: {
zIndex: caption === 'reporter-scroll-video' ? 999 : 'auto'
},
ref: embedded,
dangerouslySetInnerHTML: {
__html: nonScriptsHtml
}
}), shouldShowCaption ? /*#__PURE__*/_react.default.createElement(Caption, null, caption) : null)
);
};
exports.EmbeddedCodeBlock = EmbeddedCodeBlock;