{"version":3,"file":"index.cjs","sources":["../src/read-smore.js","../src/utils/index.js"],"sourcesContent":["import { getWordCount, getCharCount, trimSpaces } from './utils'\n;('use strict')\n\nconst defaultOptions = {\n  blockClassName: 'read-smore',\n  wordsCount: 30,\n  charsCount: null,\n  moreText: 'Read More',\n  lessText: 'Read Less',\n  isInline: false,\n  linkElement: 'a'\n}\n\n/**\n * ReadSmore\n * A simple Read More / Read Less js plugin that maintains origial markup.\n *\n * @author @stephenscaff\n * @param {HTML element} elements\n * @param {Object} options\n * @returns\n */\nfunction ReadSmore(elements, options) {\n  options = { ...defaultOptions, ...options }\n\n  // Internal Settings\n  let settings = {\n    originalContentArr: [],\n    truncatedContentArr: []\n  }\n\n  /**\n   * Init plugin\n   * Loop over instances and begin truncation procress\n   * @public\n   */\n  function init() {\n    elements.forEach((element, idx) => {\n      truncate(element, idx)\n    })\n  }\n\n  /**\n   * Is Characters\n   * Utility to check if is chars mode\n   *\n   * @private\n   * @param {HTML Elmenent} el - single element instance\n   */\n  function isChars(el) {\n    return (\n      el.dataset.readSmoreChars !== undefined || options.charsCount !== null\n    )\n  }\n\n  /**\n   * Is inline option\n   * @private\n   * @param {HTML element} el - element instance\n   * @returns {Bool}\n   */\n  function isInline(el) {\n    return el.dataset.readSmoreInline !== undefined || options.isInline === true\n  }\n\n  /**\n   * Get Count of characters or words.\n   * Favors Characters from data att, then option, then words.\n   * @private\n   * @param {HTML Elmenent} el - single element instance\n   * @returns {Number}\n   */\n  function getCount(el) {\n    return (\n      parseInt(el.dataset.readSmoreChars) ||\n      parseInt(options.charsCount) ||\n      parseInt(el.dataset.readSmoreWords) ||\n      parseInt(options.wordsCount)\n    )\n  }\n\n  /**\n   * Ellpise Content\n   * Handles content ellipse by words or charactes\n   * @private\n   * @param {String} str - content string.\n   * @param {Number} max - Number of words||chars2 to show before truncation.\n   * @param {Bool} isChars - is by chars\n   */\n  function ellipse(str, max, isChars = false) {\n    const trimmedSpaces = trimSpaces(str)\n\n    if (isChars) {\n      return trimmedSpaces.slice(0, max - 1) + '...'\n    }\n\n    const words = trimmedSpaces.split(/\\s+/)\n    return words.slice(0, max - 1).join(' ') + '...'\n  }\n\n  /**\n   * Truncate logic\n   * Gets user defined count for words/chars (set by data att, option or default),\n   * gets content's count by words/chars, if defined is less than content, truncate\n   * @private\n   * @param {HTML Elmenent} el - single element instance\n   * @param {Number} idx - current instance index\n   */\n  function truncate(el, idx) {\n    const definedCount = getCount(el)\n    const originalContent = el.innerHTML\n    const isCharMode = isChars(el)\n    const truncateContent = ellipse(originalContent, definedCount, isCharMode)\n    const originalContentCount = isCharMode\n      ? getCharCount(originalContent)\n      : getWordCount(originalContent)\n\n    settings.originalContentArr.push(originalContent)\n    settings.truncatedContentArr.push(truncateContent)\n\n    if (definedCount < originalContentCount) {\n      el.innerHTML = settings.truncatedContentArr[idx]\n      createLink(idx)\n    }\n  }\n\n  /**\n   * Creates and Inserts Read More Link\n   * @private\n   * @param {Number} idx - index reference of looped item\n   */\n  function createLink(idx) {\n    const isInlineLink = isInline(elements[idx])\n    const linkWrap = document.createElement('span')\n    linkWrap.className = `${options.blockClassName}__link-wrap`\n    linkWrap.innerHTML = linkTmpl(elements[idx])\n\n    if (isInlineLink) {\n      handleInlineStyles(elements[idx], linkWrap)\n    }\n    elements[idx].after(linkWrap)\n    setupToggleEvents(idx, isInlineLink)\n  }\n\n  /**\n   * Read More Link Template\n   * @param {HTML Element} el\n   * @returns {String} - html string\n   */\n  function linkTmpl(el) {\n    const moreTextData = el.dataset.readSmoreMoreText\n    const moreText = moreTextData || options.moreText\n    return `\n      <${options.linkElement}\n        class=\"${options.blockClassName}__link\"\n        style=\"cursor:pointer\"\n        aria-expanded=\"false\"\n        tabIndex=\"0\">\n          ${moreText}\n      </${options.linkElement}>\n    `\n  }\n\n  /**\n   * Sets up and calls click and keyup (enter key) events\n   * @private\n   * @param {Number} idx - index of clicked link\n   * @param {Bool} isInlineLink - if link element is inline with content\n   */\n  function setupToggleEvents(idx, isInlineLink) {\n    const link = elements[idx].nextSibling.firstElementChild\n    link.addEventListener('click', (event) =>\n      handleToggle(event, idx, isInlineLink)\n    )\n    link.addEventListener('keyup', (event) => {\n      if (event.keyCode === 13 && options.linkElement === 'a')\n        handleToggle(event, idx, isInlineLink)\n    })\n  }\n\n  /**\n   * Toggle event\n   * @private\n   * @param {Event} event - click | keyup event\n   * @param {Number} idx - index of clicked link\n   * @param {Bool} isInlineLink - if link element is inline with content\n   */\n  function handleToggle(event, idx, isInlineLink) {\n    const moreTextData = elements[idx].dataset.readSmoreMoreText\n    const lessTextData = elements[idx].dataset.readSmoreLessText\n    const target = event.currentTarget\n    const clicked = target.dataset.clicked === 'true'\n\n    elements[idx].classList.toggle('is-expanded')\n    elements[idx].innerHTML = clicked\n      ? settings.truncatedContentArr[idx]\n      : settings.originalContentArr[idx]\n    target.innerHTML = clicked\n      ? moreTextData || options.moreText\n      : lessTextData || options.lessText\n    target.dataset.clicked = !clicked\n    target.ariaExpanded = !clicked\n\n    if (isInlineLink) handleInlineStyles(elements[idx])\n  }\n\n  /**\n   * Add styles for inline option\n   * @private\n   * @param {HTML Elmenent} el - single element instance\n   * @param {HTML Elmenent} link - link wrapper element\n   */\n  function handleInlineStyles(el, link) {\n    if (el) {\n      el.lastElementChild.style.display = 'inline'\n      el.style.display = 'inline'\n    }\n    if (link) link.style.display = 'inline'\n  }\n\n  // API\n  return {\n    init: init\n  }\n}\n\nexport default ReadSmore\n","'use strict'\n\n/**\n * Get Character Count\n * @param {string\n * @param {number}\n */\nexport function getCharCount(str) {\n  return str.length\n}\n\n/**\n * Get Word Count\n * @param {string}\n * @param {number}\n */\nexport function getWordCount(str) {\n  const words = removeTags(str).split(' ')\n  return words.filter((word) => word.trim() !== '').length\n}\n\n/**\n * Trim whitespace\n * @param {string}\n * @param {string}\n */\nexport function trimSpaces(str) {\n  return str.replace(/(^\\s*)|(\\s*$)/gi, '')\n}\n\n/**\n * Remove HTML Tags from string\n * @param {string}\n * @param {string}\n */\nexport function removeTags(str) {\n  if (str === null || str === '') {\n    return false\n  }\n\n  return str.replace(/<[^>]+>/g, '')\n}\n"],"names":["defaultOptions","blockClassName","wordsCount","charsCount","moreText","lessText","isInline","linkElement","elements","options","_extends","settings","originalContentArr","truncatedContentArr","handleToggle","event","idx","isInlineLink","moreTextData","dataset","readSmoreMoreText","lessTextData","readSmoreLessText","target","currentTarget","clicked","classList","toggle","innerHTML","ariaExpanded","handleInlineStyles","el","link","lastElementChild","style","display","init","forEach","element","str","definedCount","parseInt","readSmoreChars","readSmoreWords","getCount","originalContent","isCharMode","undefined","isChars","truncateContent","max","trimmedSpaces","replace","trimSpaces","slice","split","join","ellipse","originalContentCount","length","filter","word","trim","push","readSmoreInline","linkWrap","document","createElement","className","linkTmpl","after","nextSibling","firstElementChild","addEventListener","keyCode","setupToggleEvents","createLink","truncate"],"mappings":"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"}