html_builders.mjs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /**
  2. * @license
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. import { createHtml, unwrapHtml } from '../internals/html_impl';
  6. import { unwrapResourceUrl } from '../internals/resource_url_impl';
  7. import { unwrapScript } from '../internals/script_impl';
  8. /**
  9. * Returns HTML-escaped text as a `SafeHtml` object.
  10. *
  11. * Available options:
  12. * - `preserveSpaces` turns every second consecutive space character into its
  13. * HTML entity representation (` `).
  14. * - `preserveNewlines` turns newline characters into breaks (`<br>`).
  15. * - `preserveTabs` wraps tab characters in a span with style=white-space:pre.
  16. */
  17. export function htmlEscape(text, options = {}) {
  18. let htmlEscapedString = htmlEscapeToString(text);
  19. if (options.preserveSpaces) {
  20. // Do this first to ensure we preserve spaces after newlines and tabs.
  21. htmlEscapedString =
  22. htmlEscapedString.replace(/(^|[\r\n\t ]) /g, '$1&#160;');
  23. }
  24. if (options.preserveNewlines) {
  25. htmlEscapedString = htmlEscapedString.replace(/(\r\n|\n|\r)/g, '<br>');
  26. }
  27. if (options.preserveTabs) {
  28. htmlEscapedString = htmlEscapedString.replace(/(\t+)/g, '<span style="white-space:pre">$1</span>');
  29. }
  30. return createHtml(htmlEscapedString);
  31. }
  32. /**
  33. * Creates a `SafeHtml` representing a script tag with inline script content.
  34. */
  35. export function createScript(script, options = {}) {
  36. const unwrappedScript = unwrapScript(script).toString();
  37. let stringTag = `<script`;
  38. if (options.id) {
  39. stringTag += ` id="${htmlEscapeToString(options.id)}"`;
  40. }
  41. if (options.nonce) {
  42. stringTag += ` nonce="${htmlEscapeToString(options.nonce)}"`;
  43. }
  44. if (options.type) {
  45. stringTag += ` type="${htmlEscapeToString(options.type)}"`;
  46. }
  47. stringTag += `>${unwrappedScript}\x3c/script>`;
  48. return createHtml(stringTag);
  49. }
  50. /**
  51. * Creates a `SafeHtml` representing a script tag with the src attribute.
  52. * This also supports CSP nonces and async loading.
  53. */
  54. export function createScriptSrc(src, async, nonce) {
  55. const unwrappedSrc = unwrapResourceUrl(src).toString();
  56. let stringTag = `<script src="${htmlEscapeToString(unwrappedSrc)}"`;
  57. if (async) {
  58. stringTag += ' async';
  59. }
  60. if (nonce) {
  61. stringTag += ` nonce="${htmlEscapeToString(nonce)}"`;
  62. }
  63. stringTag += '>\x3c/script>';
  64. return createHtml(stringTag);
  65. }
  66. /**
  67. * HTML-escapes the given text (`&`, `<`, `>`, `"` and `'`).
  68. */
  69. function htmlEscapeToString(text) {
  70. const escaped = text.replace(/&/g, '&amp;')
  71. .replace(/</g, '&lt;')
  72. .replace(/>/g, '&gt;')
  73. .replace(/"/g, '&quot;')
  74. .replace(/'/g, '&apos;');
  75. return escaped;
  76. }
  77. /** Creates a `SafeHtml` value by concatenating multiple `SafeHtml`s. */
  78. export function concatHtmls(htmls) {
  79. return createHtml(htmls.map(unwrapHtml).join(''));
  80. }