UNPKG

shave

Version:

Shave is a javascript plugin that truncates multi-line text within a html element based on set max height

1 lines 7.74 kB
{"version":3,"sources":["../src/shave.ts"],"sourcesContent":["export type Link = {\n [key: string]: string | number | boolean\n}\n\nexport type Opts = {\n character?: string\n classname?: string\n spaces?: boolean\n charclassname?: string\n link?: Link\n delimiter?: string\n}\n\nfunction generateArrayOfNodes(target: string | NodeList | Node): Array<Node> {\n if (typeof target === 'string') {\n return [...document.querySelectorAll(target)]\n } else if ('length' in target) {\n return [...target]\n } else {\n return [target]\n }\n}\n\nexport default function shave(target: string | NodeList | Node, maxHeight: number, opts: Opts = {}): void {\n if (typeof maxHeight === 'undefined' || isNaN(maxHeight)) {\n throw Error('maxHeight is required')\n }\n const els = generateArrayOfNodes(target)\n\n if (!els.length) {\n return\n }\n\n const {\n character = '…',\n classname = 'js-shave',\n spaces: initialSpaces = true,\n charclassname = 'js-shave-char',\n link = {},\n delimiter,\n } = opts\n\n /**\n * @notes\n * the initialSpaces + spaces variable definition below fixes\n * a previous bug where spaces being a boolean type wasn't clear\n * meaning people were using (a string, in example—which is truthy)\n * hence, doing it this way is a non-breaking change\n */\n const spaces = typeof initialSpaces === 'boolean' ? initialSpaces : true\n\n /**\n * @notes\n * - create a span or anchor element and assign properties to it\n * - JSON.stringify is used to support IE8+\n * - if link.href is not provided, link object properties are ignored\n */\n const isLink = link && JSON.stringify(link) !== '{}' && link.href\n const shavedTextElType = isLink ? 'a' : 'span'\n\n for (let i = 0; i < els.length; i += 1) {\n const el = els[i] as HTMLElement\n const styles = el.style\n const span = el.querySelector('.' + classname)\n const textProp = el.textContent === undefined ? 'innerText' : 'textContent'\n if (span) {\n el.removeChild(el.querySelector('.' + charclassname))\n el[textProp] = el[textProp] // eslint-disable-line\n }\n\n const fullText = el[textProp]\n let words: string | string[]\n\n if (!delimiter) words = spaces ? fullText.split(' ') : fullText\n else words = fullText.split(delimiter)\n\n if (words.length < 2) continue\n\n const heightStyle = styles.height\n styles.height = 'auto'\n const maxHeightStyle = styles.maxHeight\n styles.maxHeight = 'none'\n\n if (el.offsetHeight <= maxHeight) {\n styles.height = heightStyle\n styles.maxHeight = maxHeightStyle\n continue\n }\n\n const textContent = isLink && link.textContent ? link.textContent : character\n const shavedTextEl = document.createElement(shavedTextElType)\n const shavedTextElAttributes = {\n className: charclassname,\n textContent,\n }\n\n for (const property in shavedTextElAttributes) {\n shavedTextEl[property] = shavedTextElAttributes[property]\n shavedTextEl.textContent = character;\n }\n\n if (isLink) {\n for (const linkProperty in link) {\n shavedTextEl[linkProperty] = link[linkProperty]\n }\n }\n\n let max = words.length - 1\n let min = 0\n let pivot\n while (min < max) {\n pivot = (min + max + 1) >> 1 // eslint-disable-line no-bitwise\n const wordItems = words.slice(0, pivot);\n el[textProp] = updateTextProp(delimiter, spaces, wordItems)\n el.insertAdjacentElement('beforeend', shavedTextEl)\n if (el.offsetHeight > maxHeight) {\n max = pivot - 1\n } else {\n min = pivot\n }\n }\n const wordeItems = words.slice(0, max)\n el[textProp] = updateTextProp(delimiter, spaces, wordeItems)\n el.insertAdjacentElement('beforeend', shavedTextEl)\n const diffItems = words.slice(max);\n const isArray = Array.isArray(diffItems)\n let diff = '';\n if (delimiter && isArray) diff = delimiter + diffItems.join(delimiter)\n else if (spaces && isArray) diff = ' ' + diffItems.join(' ')\n else if (isArray) diff = diffItems.join('')\n else diff = diffItems\n const shavedText = document.createTextNode(diff)\n const elWithShavedText = document.createElement('span')\n elWithShavedText.classList.add(classname)\n elWithShavedText.style.display = 'none'\n elWithShavedText.appendChild(shavedText)\n el.insertAdjacentElement('beforeend', elWithShavedText)\n styles.height = heightStyle\n styles.maxHeight = maxHeightStyle\n }\n}\n\nexport function updateTextProp (delimiter: string, spaces: boolean, wordItems: string | string[]): string {\n const isArray = Array.isArray(wordItems)\n if (delimiter && isArray) return (wordItems).join(delimiter)\n if (spaces && isArray) return (wordItems).join(' ')\n if (isArray) return wordItems.join('')\n return wordItems\n}\n"],"mappings":"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","names":["generateArrayOfNodes","target","shave","maxHeight","opts","els","character","classname","initialSpaces","charclassname","link","delimiter","spaces","isLink","shavedTextElType","i","el","styles","span","textProp","fullText","words","heightStyle","maxHeightStyle","textContent","shavedTextEl","shavedTextElAttributes","property","linkProperty","max","min","pivot","wordItems","updateTextProp","wordeItems","diffItems","isArray","diff","shavedText","elWithShavedText"]}