this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make SVG icons more accessible?

+127 -122
+1 -8
src/components/compose.jsx
··· 31 31 import { langDetector } from '../utils/browser-translator'; 32 32 import db from '../utils/db'; 33 33 import emojifyText from '../utils/emojify-text'; 34 + import escapeHTML from '../utils/escape-html'; 34 35 import getDomain from '../utils/get-domain'; 35 36 import i18nDuration from '../utils/i18n-duration'; 36 37 import isRTL from '../utils/is-rtl'; ··· 160 161 ); 161 162 162 163 const segmenter = new Intl.Segmenter(); 163 - function escapeHTML(text) { 164 - return text 165 - .replace(/&/g, '&amp;') 166 - .replace(/</g, '&lt;') 167 - .replace(/>/g, '&gt;') 168 - .replace(/"/g, '&quot;') 169 - .replace(/'/g, '&apos;'); 170 - } 171 164 function highlightText(text, { maxCharacters = Infinity }) { 172 165 // Exceeded characters limit 173 166 const { composerCharacterCount } = states;
+16 -4
src/components/icon.jsx
··· 1 1 import moize from 'moize'; 2 2 import { useEffect, useRef, useState } from 'preact/hooks'; 3 3 4 + import escapeHTML from '../utils/escape-html'; 5 + 4 6 import { ICONS } from './ICONS'; 5 7 6 8 const SIZES = { ··· 15 17 const ICONDATA = {}; 16 18 17 19 // Memoize the dangerouslySetInnerHTML of the SVGs 20 + const INVALID_ID_CHARS_REGEX = /[^a-zA-Z0-9]/g; 18 21 const SVGICon = moize( 19 - function ({ width, height, body, rotate, flip }) { 22 + function ({ icon, title, width, height, body, rotate, flip }) { 23 + const titleID = title?.replace(INVALID_ID_CHARS_REGEX, '-') || ''; 24 + const id = `icon-${icon}-${titleID}`; 25 + const html = title 26 + ? `<title id="${id}">${escapeHTML(title)}</title>${body}` 27 + : body; 20 28 return ( 21 29 <svg 30 + role={title ? 'img' : 'presentation'} 31 + aria-labelledby={id} 22 32 viewBox={`0 0 ${width} ${height}`} 23 - dangerouslySetInnerHTML={{ __html: body }} 33 + dangerouslySetInnerHTML={{ __html: html }} 24 34 style={{ 25 35 transform: `${rotate ? `rotate(${rotate})` : ''} ${ 26 36 flip ? `scaleX(-1)` : '' ··· 33 43 isShallowEqual: true, 34 44 maxSize: Object.keys(ICONS).length, 35 45 matchesArg: (cacheKeyArg, keyArg) => 36 - cacheKeyArg.icon === keyArg.icon && cacheKeyArg.body === keyArg.body, 46 + cacheKeyArg.icon === keyArg.icon && 47 + cacheKeyArg.title === keyArg.title && 48 + cacheKeyArg.body === keyArg.body, 37 49 }, 38 50 ); 39 51 ··· 79 91 return ( 80 92 <span 81 93 class={`icon ${className} ${rtl ? 'rtl-flip' : ''}`} 82 - title={title || alt} 83 94 style={{ 84 95 width: `${iconSize}px`, 85 96 height: `${iconSize}px`, ··· 101 112 // /> 102 113 <SVGICon 103 114 icon={icon} 115 + title={title || alt} 104 116 width={iconData.width} 105 117 height={iconData.height} 106 118 body={iconData.body}
+1 -1
src/components/shortcuts.jsx
··· 166 166 } 167 167 }} 168 168 > 169 - <Icon icon={icon} size="xl" alt={title} /> 169 + <Icon icon={icon} size="xl" /> 170 170 <span> 171 171 <AsyncText>{title}</AsyncText> 172 172 {subtitle && (
+96 -96
src/locales/en.po
··· 105 105 106 106 #: src/components/account-info.jsx:457 107 107 #: src/components/account-info.jsx:1268 108 - #: src/components/compose.jsx:2819 108 + #: src/components/compose.jsx:2812 109 109 #: src/components/media-alt-modal.jsx:55 110 110 #: src/components/media-modal.jsx:363 111 111 #: src/components/status.jsx:1997 ··· 463 463 #: src/components/account-info.jsx:2212 464 464 #: src/components/account-info.jsx:2332 465 465 #: src/components/account-sheet.jsx:38 466 - #: src/components/compose.jsx:892 467 - #: src/components/compose.jsx:2775 468 - #: src/components/compose.jsx:3255 469 - #: src/components/compose.jsx:3464 470 - #: src/components/compose.jsx:3694 466 + #: src/components/compose.jsx:885 467 + #: src/components/compose.jsx:2768 468 + #: src/components/compose.jsx:3248 469 + #: src/components/compose.jsx:3457 470 + #: src/components/compose.jsx:3687 471 471 #: src/components/drafts.jsx:59 472 472 #: src/components/embed-modal.jsx:13 473 473 #: src/components/generic-accounts.jsx:151 ··· 634 634 msgid "Add to thread" 635 635 msgstr "Add to thread" 636 636 637 - #: src/components/compose.jsx:212 637 + #: src/components/compose.jsx:205 638 638 msgid "Take photo or video" 639 639 msgstr "Take photo or video" 640 640 641 - #: src/components/compose.jsx:213 641 + #: src/components/compose.jsx:206 642 642 msgid "Add media" 643 643 msgstr "Add media" 644 644 645 - #: src/components/compose.jsx:214 645 + #: src/components/compose.jsx:207 646 646 msgid "Add custom emoji" 647 647 msgstr "" 648 648 649 - #: src/components/compose.jsx:215 649 + #: src/components/compose.jsx:208 650 650 msgid "Add GIF" 651 651 msgstr "Add GIF" 652 652 653 - #: src/components/compose.jsx:216 653 + #: src/components/compose.jsx:209 654 654 msgid "Add poll" 655 655 msgstr "" 656 656 657 - #: src/components/compose.jsx:217 657 + #: src/components/compose.jsx:210 658 658 msgid "Schedule post" 659 659 msgstr "Schedule post" 660 660 661 - #: src/components/compose.jsx:417 661 + #: src/components/compose.jsx:410 662 662 msgid "You have unsaved changes. Discard this post?" 663 663 msgstr "You have unsaved changes. Discard this post?" 664 664 665 665 #. placeholder {0}: unsupportedFiles.length 666 666 #. placeholder {1}: unsupportedFiles[0].name 667 667 #. placeholder {2}: lf.format( unsupportedFiles.map((f) => f.name), ) 668 - #: src/components/compose.jsx:655 668 + #: src/components/compose.jsx:648 669 669 msgid "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}" 670 670 msgstr "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}" 671 671 672 - #: src/components/compose.jsx:665 673 - #: src/components/compose.jsx:683 674 - #: src/components/compose.jsx:1795 675 - #: src/components/compose.jsx:1930 672 + #: src/components/compose.jsx:658 673 + #: src/components/compose.jsx:676 674 + #: src/components/compose.jsx:1788 675 + #: src/components/compose.jsx:1923 676 676 msgid "{maxMediaAttachments, plural, one {You can only attach up to 1 file.} other {You can only attach up to # files.}}" 677 677 msgstr "" 678 678 679 - #: src/components/compose.jsx:873 679 + #: src/components/compose.jsx:866 680 680 msgid "Pop out" 681 681 msgstr "Pop out" 682 682 683 - #: src/components/compose.jsx:880 683 + #: src/components/compose.jsx:873 684 684 msgid "Minimize" 685 685 msgstr "Minimize" 686 686 687 - #: src/components/compose.jsx:916 687 + #: src/components/compose.jsx:909 688 688 msgid "Looks like you closed the parent window." 689 689 msgstr "Looks like you closed the parent window." 690 690 691 - #: src/components/compose.jsx:923 691 + #: src/components/compose.jsx:916 692 692 msgid "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later." 693 693 msgstr "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later." 694 694 695 - #: src/components/compose.jsx:928 695 + #: src/components/compose.jsx:921 696 696 msgid "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?" 697 697 msgstr "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?" 698 698 699 - #: src/components/compose.jsx:971 699 + #: src/components/compose.jsx:964 700 700 msgid "Pop in" 701 701 msgstr "Pop in" 702 702 703 703 #. placeholder {0}: replyToStatus.account.acct || replyToStatus.account.username 704 704 #. placeholder {1}: rtf.format(-replyToStatusMonthsAgo, 'month') 705 - #: src/components/compose.jsx:981 705 + #: src/components/compose.jsx:974 706 706 msgid "Replying to @{0}’s post (<0>{1}</0>)" 707 707 msgstr "" 708 708 709 709 #. placeholder {0}: replyToStatus.account.acct || replyToStatus.account.username 710 - #: src/components/compose.jsx:991 710 + #: src/components/compose.jsx:984 711 711 msgid "Replying to @{0}’s post" 712 712 msgstr "" 713 713 714 - #: src/components/compose.jsx:1004 714 + #: src/components/compose.jsx:997 715 715 msgid "Editing source post" 716 716 msgstr "" 717 717 718 - #: src/components/compose.jsx:1057 718 + #: src/components/compose.jsx:1050 719 719 msgid "Poll must have at least 2 options" 720 720 msgstr "Poll must have at least 2 options" 721 721 722 - #: src/components/compose.jsx:1061 722 + #: src/components/compose.jsx:1054 723 723 msgid "Some poll choices are empty" 724 724 msgstr "Some poll choices are empty" 725 725 726 - #: src/components/compose.jsx:1074 726 + #: src/components/compose.jsx:1067 727 727 msgid "Some media have no descriptions. Continue?" 728 728 msgstr "Some media have no descriptions. Continue?" 729 729 730 - #: src/components/compose.jsx:1126 730 + #: src/components/compose.jsx:1119 731 731 msgid "Attachment #{i} failed" 732 732 msgstr "Attachment #{i} failed" 733 733 734 - #: src/components/compose.jsx:1222 734 + #: src/components/compose.jsx:1215 735 735 #: src/components/status.jsx:2329 736 736 #: src/components/timeline.jsx:1015 737 737 msgid "Content warning" 738 738 msgstr "" 739 739 740 - #: src/components/compose.jsx:1238 740 + #: src/components/compose.jsx:1231 741 741 msgid "Content warning or sensitive media" 742 742 msgstr "Content warning or sensitive media" 743 743 744 - #: src/components/compose.jsx:1274 744 + #: src/components/compose.jsx:1267 745 745 #: src/components/status.jsx:100 746 746 #: src/pages/settings.jsx:318 747 747 msgid "Public" 748 748 msgstr "" 749 749 750 - #: src/components/compose.jsx:1279 750 + #: src/components/compose.jsx:1272 751 751 #: src/components/nav-menu.jsx:349 752 752 #: src/components/shortcuts-settings.jsx:165 753 753 #: src/components/status.jsx:101 754 754 msgid "Local" 755 755 msgstr "" 756 756 757 - #: src/components/compose.jsx:1283 757 + #: src/components/compose.jsx:1276 758 758 #: src/components/status.jsx:102 759 759 #: src/pages/settings.jsx:321 760 760 msgid "Unlisted" 761 761 msgstr "" 762 762 763 - #: src/components/compose.jsx:1286 763 + #: src/components/compose.jsx:1279 764 764 #: src/components/status.jsx:103 765 765 #: src/pages/settings.jsx:324 766 766 msgid "Followers only" 767 767 msgstr "" 768 768 769 - #: src/components/compose.jsx:1289 769 + #: src/components/compose.jsx:1282 770 770 #: src/components/status.jsx:104 771 771 #: src/components/status.jsx:2209 772 772 msgid "Private mention" 773 773 msgstr "" 774 774 775 - #: src/components/compose.jsx:1298 775 + #: src/components/compose.jsx:1291 776 776 msgid "Post your reply" 777 777 msgstr "Post your reply" 778 778 779 - #: src/components/compose.jsx:1300 779 + #: src/components/compose.jsx:1293 780 780 msgid "Edit your post" 781 781 msgstr "Edit your post" 782 782 783 - #: src/components/compose.jsx:1301 783 + #: src/components/compose.jsx:1294 784 784 msgid "What are you doing?" 785 785 msgstr "What are you doing?" 786 786 787 - #: src/components/compose.jsx:1380 787 + #: src/components/compose.jsx:1373 788 788 msgid "Mark media as sensitive" 789 789 msgstr "" 790 790 791 - #: src/components/compose.jsx:1417 791 + #: src/components/compose.jsx:1410 792 792 msgid "Posting on <0/>" 793 793 msgstr "Posting on <0/>" 794 794 795 - #: src/components/compose.jsx:1448 796 - #: src/components/compose.jsx:3313 795 + #: src/components/compose.jsx:1441 796 + #: src/components/compose.jsx:3306 797 797 #: src/components/shortcuts-settings.jsx:715 798 798 #: src/pages/list.jsx:388 799 799 msgid "Add" 800 800 msgstr "" 801 801 802 - #: src/components/compose.jsx:1676 802 + #: src/components/compose.jsx:1669 803 803 msgid "Schedule" 804 804 msgstr "Schedule" 805 805 806 - #: src/components/compose.jsx:1678 806 + #: src/components/compose.jsx:1671 807 807 #: src/components/keyboard-shortcuts-help.jsx:155 808 808 #: src/components/status.jsx:1191 809 809 #: src/components/status.jsx:1977 ··· 812 812 msgid "Reply" 813 813 msgstr "" 814 814 815 - #: src/components/compose.jsx:1680 815 + #: src/components/compose.jsx:1673 816 816 msgid "Update" 817 817 msgstr "Update" 818 818 819 - #: src/components/compose.jsx:1681 819 + #: src/components/compose.jsx:1674 820 820 msgctxt "Submit button in composer" 821 821 msgid "Post" 822 822 msgstr "Post" 823 823 824 - #: src/components/compose.jsx:1807 824 + #: src/components/compose.jsx:1800 825 825 msgid "Downloading GIF…" 826 826 msgstr "Downloading GIF…" 827 827 828 - #: src/components/compose.jsx:1835 828 + #: src/components/compose.jsx:1828 829 829 msgid "Failed to download GIF" 830 830 msgstr "Failed to download GIF" 831 831 832 - #: src/components/compose.jsx:2060 833 - #: src/components/compose.jsx:2153 832 + #: src/components/compose.jsx:2053 833 + #: src/components/compose.jsx:2146 834 834 #: src/components/nav-menu.jsx:244 835 835 msgid "More…" 836 836 msgstr "" 837 837 838 - #: src/components/compose.jsx:2589 838 + #: src/components/compose.jsx:2582 839 839 msgid "Uploaded" 840 840 msgstr "" 841 841 842 - #: src/components/compose.jsx:2602 842 + #: src/components/compose.jsx:2595 843 843 msgid "Image description" 844 844 msgstr "Image description" 845 845 846 - #: src/components/compose.jsx:2603 846 + #: src/components/compose.jsx:2596 847 847 msgid "Video description" 848 848 msgstr "Video description" 849 849 850 - #: src/components/compose.jsx:2604 850 + #: src/components/compose.jsx:2597 851 851 msgid "Audio description" 852 852 msgstr "Audio description" 853 853 ··· 855 855 #. placeholder {0}: prettyBytes( videoSize, ) 856 856 #. placeholder {1}: prettyBytes(imageSizeLimit) 857 857 #. placeholder {1}: prettyBytes(videoSizeLimit) 858 - #: src/components/compose.jsx:2639 859 - #: src/components/compose.jsx:2659 858 + #: src/components/compose.jsx:2632 859 + #: src/components/compose.jsx:2652 860 860 msgid "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower." 861 861 msgstr "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower." 862 862 ··· 864 864 #. placeholder {1}: i18n.number(height) 865 865 #. placeholder {2}: i18n.number(newWidth) 866 866 #. placeholder {3}: i18n.number( newHeight, ) 867 - #: src/components/compose.jsx:2651 868 - #: src/components/compose.jsx:2671 867 + #: src/components/compose.jsx:2644 868 + #: src/components/compose.jsx:2664 869 869 msgid "Dimension too large. Uploading might encounter issues. Try reduce dimension from {0}×{1}px to {2}×{3}px." 870 870 msgstr "Dimension too large. Uploading might encounter issues. Try reduce dimension from {0}×{1}px to {2}×{3}px." 871 871 872 - #: src/components/compose.jsx:2679 872 + #: src/components/compose.jsx:2672 873 873 msgid "Frame rate too high. Uploading might encounter issues." 874 874 msgstr "Frame rate too high. Uploading might encounter issues." 875 875 876 - #: src/components/compose.jsx:2739 877 - #: src/components/compose.jsx:2989 876 + #: src/components/compose.jsx:2732 877 + #: src/components/compose.jsx:2982 878 878 #: src/components/shortcuts-settings.jsx:726 879 879 #: src/pages/catchup.jsx:1081 880 880 #: src/pages/filters.jsx:413 881 881 msgid "Remove" 882 882 msgstr "" 883 883 884 - #: src/components/compose.jsx:2756 884 + #: src/components/compose.jsx:2749 885 885 #: src/compose.jsx:84 886 886 msgid "Error" 887 887 msgstr "" 888 888 889 - #: src/components/compose.jsx:2781 889 + #: src/components/compose.jsx:2774 890 890 msgid "Edit image description" 891 891 msgstr "Edit image description" 892 892 893 - #: src/components/compose.jsx:2782 893 + #: src/components/compose.jsx:2775 894 894 msgid "Edit video description" 895 895 msgstr "Edit video description" 896 896 897 - #: src/components/compose.jsx:2783 897 + #: src/components/compose.jsx:2776 898 898 msgid "Edit audio description" 899 899 msgstr "Edit audio description" 900 900 901 - #: src/components/compose.jsx:2828 902 - #: src/components/compose.jsx:2877 901 + #: src/components/compose.jsx:2821 902 + #: src/components/compose.jsx:2870 903 903 msgid "Generating description. Please wait…" 904 904 msgstr "Generating description. Please wait…" 905 905 906 906 #. placeholder {0}: e.message 907 - #: src/components/compose.jsx:2848 907 + #: src/components/compose.jsx:2841 908 908 msgid "Failed to generate description: {0}" 909 909 msgstr "Failed to generate description: {0}" 910 910 911 - #: src/components/compose.jsx:2849 911 + #: src/components/compose.jsx:2842 912 912 msgid "Failed to generate description" 913 913 msgstr "Failed to generate description" 914 914 915 - #: src/components/compose.jsx:2861 916 - #: src/components/compose.jsx:2867 917 - #: src/components/compose.jsx:2913 915 + #: src/components/compose.jsx:2854 916 + #: src/components/compose.jsx:2860 917 + #: src/components/compose.jsx:2906 918 918 msgid "Generate description…" 919 919 msgstr "" 920 920 921 921 #. placeholder {0}: e?.message ? `: ${e.message}` : '' 922 - #: src/components/compose.jsx:2900 922 + #: src/components/compose.jsx:2893 923 923 msgid "Failed to generate description{0}" 924 924 msgstr "Failed to generate description{0}" 925 925 926 926 #. placeholder {0}: localeCode2Text(lang) 927 - #: src/components/compose.jsx:2915 927 + #: src/components/compose.jsx:2908 928 928 msgid "({0}) <0>— experimental</0>" 929 929 msgstr "" 930 930 931 - #: src/components/compose.jsx:2934 931 + #: src/components/compose.jsx:2927 932 932 msgid "Done" 933 933 msgstr "" 934 934 935 935 #. placeholder {0}: i + 1 936 - #: src/components/compose.jsx:2970 936 + #: src/components/compose.jsx:2963 937 937 msgid "Choice {0}" 938 938 msgstr "Choice {0}" 939 939 940 - #: src/components/compose.jsx:3017 940 + #: src/components/compose.jsx:3010 941 941 msgid "Multiple choices" 942 942 msgstr "" 943 943 944 - #: src/components/compose.jsx:3020 944 + #: src/components/compose.jsx:3013 945 945 msgid "Duration" 946 946 msgstr "" 947 947 948 - #: src/components/compose.jsx:3051 948 + #: src/components/compose.jsx:3044 949 949 msgid "Remove poll" 950 950 msgstr "" 951 951 952 - #: src/components/compose.jsx:3272 952 + #: src/components/compose.jsx:3265 953 953 msgid "Search accounts" 954 954 msgstr "Search accounts" 955 955 956 - #: src/components/compose.jsx:3326 956 + #: src/components/compose.jsx:3319 957 957 #: src/components/generic-accounts.jsx:236 958 958 msgid "Error loading accounts" 959 959 msgstr "" 960 960 961 - #: src/components/compose.jsx:3470 961 + #: src/components/compose.jsx:3463 962 962 msgid "Custom emojis" 963 963 msgstr "" 964 964 965 - #: src/components/compose.jsx:3490 965 + #: src/components/compose.jsx:3483 966 966 msgid "Search emoji" 967 967 msgstr "Search emoji" 968 968 969 - #: src/components/compose.jsx:3521 969 + #: src/components/compose.jsx:3514 970 970 msgid "Error loading custom emojis" 971 971 msgstr "" 972 972 973 - #: src/components/compose.jsx:3532 973 + #: src/components/compose.jsx:3525 974 974 msgid "Recently used" 975 975 msgstr "Recently used" 976 976 977 - #: src/components/compose.jsx:3533 977 + #: src/components/compose.jsx:3526 978 978 msgid "Others" 979 979 msgstr "Others" 980 980 981 981 #. placeholder {0}: i18n.number(emojis.length - max) 982 - #: src/components/compose.jsx:3571 982 + #: src/components/compose.jsx:3564 983 983 msgid "{0} more…" 984 984 msgstr "" 985 985 986 - #: src/components/compose.jsx:3709 986 + #: src/components/compose.jsx:3702 987 987 msgid "Search GIFs" 988 988 msgstr "Search GIFs" 989 989 990 - #: src/components/compose.jsx:3724 990 + #: src/components/compose.jsx:3717 991 991 msgid "Powered by GIPHY" 992 992 msgstr "Powered by GIPHY" 993 993 994 - #: src/components/compose.jsx:3732 994 + #: src/components/compose.jsx:3725 995 995 msgid "Type to search GIFs" 996 996 msgstr "" 997 997 998 - #: src/components/compose.jsx:3830 998 + #: src/components/compose.jsx:3823 999 999 #: src/components/media-modal.jsx:469 1000 1000 #: src/components/timeline.jsx:928 1001 1001 msgid "Previous" 1002 1002 msgstr "" 1003 1003 1004 - #: src/components/compose.jsx:3848 1004 + #: src/components/compose.jsx:3841 1005 1005 #: src/components/media-modal.jsx:488 1006 1006 #: src/components/timeline.jsx:945 1007 1007 msgid "Next" 1008 1008 msgstr "" 1009 1009 1010 - #: src/components/compose.jsx:3865 1010 + #: src/components/compose.jsx:3858 1011 1011 msgid "Error loading GIFs" 1012 1012 msgstr "" 1013 1013
+1 -13
src/utils/enhance-content.js
··· 1 1 import emojifyText from './emojify-text'; 2 + import escapeHTML from './escape-html'; 2 3 import mem from './mem'; 3 4 4 5 const fauxDiv = document.createElement('div'); 5 6 const whitelistLinkClasses = ['u-url', 'mention', 'hashtag']; 6 - 7 - const HTML_CHARS_REGEX = /[&<>]/g; 8 - function escapeHTML(html) { 9 - return html.replace( 10 - HTML_CHARS_REGEX, 11 - (c) => 12 - ({ 13 - '&': '&amp;', 14 - '<': '&lt;', 15 - '>': '&gt;', 16 - })[c], 17 - ); 18 - } 19 7 20 8 const LINK_REGEX = /<a/i; 21 9 const HTTP_LINK_REGEX = /^https?:\/\//i;
+12
src/utils/escape-html.js
··· 1 + const HTML_CHARS_REGEX = /[&<>"']/g; 2 + const HTML_ENTITIES = { 3 + '&': '&amp;', 4 + '<': '&lt;', 5 + '>': '&gt;', 6 + '"': '&quot;', 7 + "'": '&apos;', 8 + }; 9 + 10 + export default function escapeHTML(text) { 11 + return text.replace(HTML_CHARS_REGEX, (c) => HTML_ENTITIES[c]); 12 + }