1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5import { Localized } from "fluent-react"; 6import React from "react"; 7import { RICH_TEXT_KEYS } from "../../rich-text-strings"; 8import { safeURI } from "../../template-utils"; 9 10// Elements allowed in snippet content 11const ALLOWED_TAGS = { 12 b: <b />, 13 i: <i />, 14 u: <u />, 15 strong: <strong />, 16 em: <em />, 17 br: <br />, 18}; 19 20/** 21 * Transform an object (tag name: {url}) into (tag name: anchor) where the url 22 * is used as href, in order to render links inside a Fluent.Localized component. 23 */ 24export function convertLinks( 25 links, 26 sendClick, 27 doNotAutoBlock, 28 openNewWindow = false 29) { 30 if (links) { 31 return Object.keys(links).reduce((acc, linkTag) => { 32 const { action } = links[linkTag]; 33 // Setting the value to false will not include the attribute in the anchor 34 const url = action ? false : safeURI(links[linkTag].url); 35 36 acc[linkTag] = ( 37 // eslint was getting a false positive caused by the dynamic injection 38 // of content. 39 // eslint-disable-next-line jsx-a11y/anchor-has-content 40 <a 41 href={url} 42 target={openNewWindow ? "_blank" : ""} 43 data-metric={links[linkTag].metric} 44 data-action={action} 45 data-args={links[linkTag].args} 46 data-do_not_autoblock={doNotAutoBlock} 47 data-entrypoint_name={links[linkTag].entrypoint_name} 48 data-entrypoint_value={links[linkTag].entrypoint_value} 49 rel="noreferrer" 50 onClick={sendClick} 51 /> 52 ); 53 return acc; 54 }, {}); 55 } 56 57 return null; 58} 59 60/** 61 * Message wrapper used to sanitize markup and render HTML. 62 */ 63export function RichText(props) { 64 if (!RICH_TEXT_KEYS.includes(props.localization_id)) { 65 throw new Error( 66 `ASRouter: ${props.localization_id} is not a valid rich text property. If you want it to be processed, you need to add it to asrouter/rich-text-strings.js` 67 ); 68 } 69 return ( 70 <Localized 71 id={props.localization_id} 72 {...ALLOWED_TAGS} 73 {...props.customElements} 74 {...convertLinks( 75 props.links, 76 props.sendClick, 77 props.doNotAutoBlock, 78 props.openNewWindow 79 )} 80 > 81 <span>{props.text}</span> 82 </Localized> 83 ); 84} 85