{"version":3,"file":"ReadMore-Bz7duiP5.js","sources":["../../../node_modules/html-truncate/lib/truncate.js","../../../frontend/src/Components/ReadMore/ReadMore.tsx"],"sourcesContent":["/**\n * Truncate HTML string and keep tag safe.\n *\n * @method truncate\n * @param {String} string string needs to be truncated\n * @param {Number} maxLength length of truncated string\n * @param {Object} options (optional)\n * @param {Boolean} [options.keepImageTag] flag to specify if keep image tag, false by default\n * @param {Boolean} [options.truncateLastWord] truncates last word, true by default\n * @param {Number} [options.slop] tolerance when options.truncateLastWord is false before we give up and just truncate at the maxLength position, 10 by default (but not greater than maxLength)\n * @param {Boolean|String} [options.ellipsis] omission symbol for truncated string, '...' by default\n * @return {String} truncated string\n */\nfunction truncate(string, maxLength, options) {\n    var EMPTY_OBJECT = {},\n        EMPTY_STRING = '',\n        DEFAULT_TRUNCATE_SYMBOL = '...',\n        DEFAULT_SLOP = 10 > maxLength ? maxLength : 10,\n        EXCLUDE_TAGS = ['img', 'br'],   // non-closed tags\n        items = [],                     // stack for saving tags\n        total = 0,                      // record how many characters we traced so far\n        content = EMPTY_STRING,         // truncated text storage\n        KEY_VALUE_REGEX = '([\\\\w|-]+\\\\s*(=\\\\s*\"[^\"]*\")?\\\\s*)*',\n        IS_CLOSE_REGEX = '\\\\s*\\\\/?\\\\s*',\n        CLOSE_REGEX = '\\\\s*\\\\/\\\\s*',\n        SELF_CLOSE_REGEX = new RegExp('<\\\\/?\\\\w+\\\\s*' + KEY_VALUE_REGEX + CLOSE_REGEX + '>'),\n        HTML_TAG_REGEX = new RegExp('<\\\\/?\\\\w+\\\\s*' + KEY_VALUE_REGEX + IS_CLOSE_REGEX + '>'),\n        URL_REGEX = /(((ftp|https?):\\/\\/)[\\-\\w@:%_\\+.~#?,&\\/\\/=]+)|((mailto:)?[_.\\w\\-]+@([\\w][\\w\\-]+\\.)+[a-zA-Z]{2,3})/g, // Simple regexp\n        IMAGE_TAG_REGEX = new RegExp('<img\\\\s*' + KEY_VALUE_REGEX + IS_CLOSE_REGEX + '>'),\n        WORD_BREAK_REGEX = new RegExp('\\\\W+', 'g'),\n        matches = true,\n        result,\n        index,\n        tail,\n        tag,\n        selfClose;\n\n    /**\n     * Remove image tag\n     *\n     * @private\n     * @method _removeImageTag\n     * @param {String} string not-yet-processed string\n     * @return {String} string without image tags\n     */\n    function _removeImageTag(string) {\n        var match = IMAGE_TAG_REGEX.exec(string),\n            index,\n            len;\n\n        if (!match) {\n            return string;\n        }\n\n        index = match.index;\n        len = match[0].length;\n\n        return string.substring(0, index) + string.substring(index + len);\n    }\n\n    /**\n     * Dump all close tags and append to truncated content while reaching upperbound\n     *\n     * @private\n     * @method _dumpCloseTag\n     * @param {String[]} tags a list of tags which should be closed\n     * @return {String} well-formatted html\n     */\n    function _dumpCloseTag(tags) {\n        var html = '';\n\n        tags.reverse().forEach(function (tag, index) {\n            // dump non-excluded tags only\n            if (-1 === EXCLUDE_TAGS.indexOf(tag)) {\n                html += '</' + tag + '>';\n            }\n        });\n\n        return html;\n    }\n\n    /**\n     * Process tag string to get pure tag name\n     *\n     * @private\n     * @method _getTag\n     * @param {String} string original html\n     * @return {String} tag name\n     */\n    function _getTag(string) {\n        var tail = string.indexOf(' ');\n\n        // TODO:\n        // we have to figure out how to handle non-well-formatted HTML case\n        if (-1 === tail) {\n            tail = string.indexOf('>');\n            if (-1 === tail) {\n                throw new Error('HTML tag is not well-formed : ' + string);\n            }\n        }\n\n        return string.substring(1, tail);\n    }\n\n\n    /**\n     * Get the end position for String#substring()\n     *\n     * If options.truncateLastWord is FALSE, we try to the end position up to\n     * options.slop characters to avoid breaking in the middle of a word.\n     *\n     * @private\n     * @method _getEndPosition\n     * @param {String} string original html\n     * @param {Number} tailPos (optional) provided to avoid extending the slop into trailing HTML tag\n     * @return {Number} maxLength\n     */\n    function _getEndPosition (string, tailPos) {\n        var defaultPos = maxLength - total,\n            position = defaultPos,\n            isShort = defaultPos < options.slop,\n            slopPos = isShort ? defaultPos : options.slop - 1,\n            substr,\n            startSlice = isShort ? 0 : defaultPos - options.slop,\n            endSlice = tailPos || (defaultPos + options.slop),\n            result;\n\n        if (!options.truncateLastWord) {\n\n            substr = string.slice(startSlice, endSlice);\n\n            if (tailPos && substr.length <= tailPos) {\n                position = substr.length;\n            }\n            else {\n                while ((result = WORD_BREAK_REGEX.exec(substr)) !== null) {\n                    // a natural break position before the hard break position\n                    if (result.index < slopPos) {\n                        position = defaultPos - (slopPos - result.index);\n                        // keep seeking closer to the hard break position\n                        // unless a natural break is at position 0\n                        if (result.index === 0 && defaultPos <= 1) break;\n                    }\n                    // a natural break position exactly at the hard break position\n                    else if (result.index === slopPos) {\n                        position = defaultPos;\n                        break; // seek no more\n                    }\n                    // a natural break position after the hard break position\n                    else {\n                        position = defaultPos + (result.index - slopPos);\n                        break;  // seek no more\n                    }\n                }\n            }\n            if (string.charAt(position - 1).match(/\\s$/)) position--;\n        }\n        return position;\n    }\n\n    options = options || EMPTY_OBJECT;\n    options.ellipsis = (undefined !== options.ellipsis) ? options.ellipsis : DEFAULT_TRUNCATE_SYMBOL;\n    options.truncateLastWord = (undefined !== options.truncateLastWord) ? options.truncateLastWord : true;\n    options.slop = (undefined !== options.slop) ? options.slop : DEFAULT_SLOP;\n\n    while (matches) {\n        matches = HTML_TAG_REGEX.exec(string);\n\n        if (!matches) {\n            if (total >= maxLength) { break; }\n\n            matches = URL_REGEX.exec(string);\n            if (!matches || matches.index >= maxLength) {\n                content += string.substring(0, _getEndPosition(string));\n                break;\n            }\n\n            while (matches) {\n                result = matches[0];\n                index = matches.index;\n                content += string.substring(0, (index + result.length) - total);\n                string = string.substring(index + result.length);\n                matches = URL_REGEX.exec(string);\n            }\n            break;\n        }\n\n        result = matches[0];\n        index = matches.index;\n\n        if (total + index > maxLength) {\n            // exceed given `maxLength`, dump everything to clear stack\n            content += string.substring(0, _getEndPosition(string, index));\n            break;\n        } else {\n            total += index;\n            content += string.substring(0, index);\n        }\n\n        if ('/' === result[1]) {\n            // move out open tag\n            items.pop();\n            selfClose=null;\n        } else {\n            selfClose = SELF_CLOSE_REGEX.exec(result);\n            if (!selfClose) {\n                tag = _getTag(result);\n\n                items.push(tag);\n            }\n        }\n\n        if (selfClose) {\n            content += selfClose[0];\n        } else {\n            content += result;\n        }\n        string = string.substring(index + result.length);\n    }\n\n    if (string.length > maxLength - total && options.ellipsis) {\n        content += options.ellipsis;\n    }\n    content += _dumpCloseTag(items);\n\n    if (!options.keepImageTag) {\n        content = _removeImageTag(content);\n    }\n\n    return content;\n}\n\nmodule.exports = truncate;\n","import React, { useState } from 'react';\nimport { Link as ButtonLink } from '@mui/material';\nimport { FormattedMessage } from 'react-intl';\nimport PropTypes from 'prop-types';\nimport truncate from 'html-truncate';\n\nimport { HtmlToMUIMapper, stripHtml } from '../../Utils';\n\nfunction ReadMore({ content, maxLength = 1000, expand = true }: any) {\n  const [open, setOpen] = useState(false);\n  const stripedContent = stripHtml(content);\n  const truncatedContent = truncate(content, maxLength, { ellipsis: '…' });\n  const displayReadMore = stripedContent.length > maxLength;\n\n  if (expand || open || !displayReadMore) {\n    return <HtmlToMUIMapper content={content} />;\n  }\n\n  return (\n    <>\n      <HtmlToMUIMapper content={truncatedContent} />\n\n      {displayReadMore && (\n        <ButtonLink\n          component=\"button\"\n          onClick={() => setOpen(!open)}\n          variant=\"body1\"\n          underline=\"hover\"\n          sx={{ ml: 1 }}\n        >\n          <strong>\n            <FormattedMessage id=\"BUTTONS.READ_MORE\" />\n          </strong>\n        </ButtonLink>\n      )}\n    </>\n  );\n}\n\nReadMore.propTypes = {\n  content: PropTypes.string.isRequired,\n  maxLength: PropTypes.number,\n  expand: PropTypes.bool,\n};\n\nexport default ReadMore;\n"],"names":["truncate","string","maxLength","options","EMPTY_OBJECT","EMPTY_STRING","DEFAULT_TRUNCATE_SYMBOL","DEFAULT_SLOP","EXCLUDE_TAGS","items","total","content","KEY_VALUE_REGEX","IS_CLOSE_REGEX","CLOSE_REGEX","SELF_CLOSE_REGEX","HTML_TAG_REGEX","URL_REGEX","IMAGE_TAG_REGEX","WORD_BREAK_REGEX","matches","result","index","tag","selfClose","_removeImageTag","match","len","_dumpCloseTag","tags","html","_getTag","tail","_getEndPosition","tailPos","defaultPos","position","isShort","slopPos","substr","startSlice","endSlice","truncate_1","ReadMore","_ref","_ref$maxLength","_ref$expand","expand","_useState","useState","_useState2","_slicedToArray","open","setOpen","stripedContent","stripHtml","truncatedContent","ellipsis","displayReadMore","length","React","createElement","HtmlToMUIMapper","Fragment","ButtonLink","component","onClick","variant","underline","sx","ml","FormattedMessage","id","propTypes","PropTypes","isRequired","number","bool"],"mappings":"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","x_google_ignoreList":[0]}