mirror of
https://github.com/arthur-pbty/portfolio2023.git
synced 2026-06-03 23:36:21 +02:00
189 lines
7.8 KiB
JavaScript
189 lines
7.8 KiB
JavaScript
(function(exportTo) {
|
|
"use strict";
|
|
|
|
var selfClosingTags = ["area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"];
|
|
|
|
/**
|
|
* Truncates a given HTML string to the specified length.
|
|
* @param {string} text This is the HTMl string to be truncated
|
|
* @param {object} options An options object defining how to truncate
|
|
* Default values:
|
|
* {
|
|
* TruncateBy : 'words', // Options are 'words', 'characters' or 'paragraphs'
|
|
* TruncateLength : 50, // The count to be used with TruncatedBy
|
|
* StripHTML : false, // Whether or not the truncated text should contain HTML tags
|
|
* Strict : true, // When set to false the truncated text finish at the end of the word
|
|
* Suffix : '...' // Text to be appended to the end of the truncated text
|
|
* }
|
|
* @return {string} This returns the provided string truncated to the
|
|
* length provided by the options. HTML tags may be stripped based
|
|
* on the given options.
|
|
*/
|
|
var truncatise = function(text,options) {
|
|
var options = options || {},
|
|
text = (text || "").trim(),
|
|
truncatedText = "",
|
|
currentState = 0,
|
|
isEndOfWord = false,
|
|
isTagOpen = false,
|
|
currentTag = "",
|
|
tagStack = [],
|
|
nextChar = "";
|
|
//Counters
|
|
var charCounter = 0,
|
|
wordCounter = 0,
|
|
paragraphCounter = 0;
|
|
//currentState values
|
|
var NOT_TAG = 0,
|
|
TAG_START = 1,
|
|
TAG_ATTRIBUTES = 2;
|
|
|
|
//Set default values
|
|
options.TruncateBy = (options.TruncateBy === undefined
|
|
|| typeof options.TruncateBy !== "string"
|
|
|| !options.TruncateBy.match(/(word(s)?|character(s)?|paragraph(s)?)/))
|
|
? 'words'
|
|
: options.TruncateBy.toLowerCase();
|
|
options.TruncateLength = (options.TruncateLength === undefined
|
|
|| typeof options.TruncateLength !== "number")
|
|
? 50
|
|
: options.TruncateLength;
|
|
options.StripHTML = (options.StripHTML === undefined
|
|
|| typeof options.StripHTML !== "boolean")
|
|
? false
|
|
: options.StripHTML;
|
|
options.Strict = (options.Strict === undefined
|
|
|| typeof options.Strict !== "boolean")
|
|
? true
|
|
: options.Strict;
|
|
options.Suffix = (options.Suffix === undefined
|
|
|| typeof options.Suffix !== "string")
|
|
? '...'
|
|
: options.Suffix;
|
|
|
|
if(text === "" || (text.length <= options.TruncateLength && options.StripHTML === false)){
|
|
return text;
|
|
}
|
|
|
|
if(options.StripHTML) {
|
|
text = String(text).replace(/<br( \/)?>/gi, ' ');
|
|
}
|
|
|
|
//If not splitting on paragraphs we can quickly remove tags using regex
|
|
if(options.StripHTML && !options.TruncateBy.match(/(paragraph(s)?)/)){
|
|
text = String(text).replace(/<!--(.*?)-->/gm, '').replace(/<\/?[^>]+>/gi, '');
|
|
}
|
|
//Remove newline seperating paragraphs
|
|
text = String(text).replace(/<\/p>(\r?\n)+<p>/gm, '</p><p>');
|
|
//Replace double newlines with paragraphs
|
|
if(options.StripHTML && String(text).match(/\r?\n\r?\n/)){
|
|
text = String(text).replace(/((.+)(\r?\n\r?\n|$))/gi, "<p>$2</p>");
|
|
}
|
|
|
|
for (var pointer = 0; pointer < text.length; pointer++ ) {
|
|
|
|
var currentChar = text[pointer];
|
|
|
|
switch(currentChar){
|
|
case "<":
|
|
if(currentState === NOT_TAG){
|
|
currentState = TAG_START;
|
|
currentTag = "";
|
|
}
|
|
if(!options.StripHTML){
|
|
truncatedText += currentChar;
|
|
}
|
|
break;
|
|
case ">":
|
|
if(currentState === TAG_START || currentState === TAG_ATTRIBUTES){
|
|
currentState = NOT_TAG;
|
|
currentTag = currentTag.toLowerCase();
|
|
if(currentTag === "/p"){
|
|
paragraphCounter++;
|
|
if(options.StripHTML){
|
|
truncatedText += " ";
|
|
}
|
|
}
|
|
|
|
// Ignore self-closing tags.
|
|
if ((selfClosingTags.indexOf(currentTag) === -1) && (selfClosingTags.indexOf(currentTag + '/') === -1)) {
|
|
if(currentTag.indexOf("/") >= 0){
|
|
tagStack.pop();
|
|
} else {
|
|
tagStack.push(currentTag);
|
|
}
|
|
}
|
|
}
|
|
if(!options.StripHTML){
|
|
truncatedText += currentChar;
|
|
}
|
|
break;
|
|
case " ":
|
|
if(currentState === TAG_START){
|
|
currentState = TAG_ATTRIBUTES;
|
|
}
|
|
if(currentState === NOT_TAG){
|
|
wordCounter++;
|
|
charCounter++;
|
|
}
|
|
if(currentState === NOT_TAG || !options.StripHTML){
|
|
truncatedText += currentChar;
|
|
}
|
|
break;
|
|
default:
|
|
if(currentState === NOT_TAG){
|
|
charCounter++;
|
|
}
|
|
if(currentState === TAG_START){
|
|
currentTag += currentChar;
|
|
}
|
|
if(currentState === NOT_TAG || !options.StripHTML){
|
|
truncatedText += currentChar;
|
|
}
|
|
break;
|
|
}
|
|
|
|
nextChar = text[pointer + 1] || "";
|
|
isEndOfWord = options.Strict ? true : (!currentChar.match(/[a-zA-ZÇ-Ü']/i) || !nextChar.match(/[a-zA-ZÇ-Ü']/i));
|
|
|
|
if(options.TruncateBy.match(/word(s)?/i) && options.TruncateLength <= wordCounter){
|
|
truncatedText = truncatedText.replace(/\s+$/, '');
|
|
break;
|
|
}
|
|
if(options.TruncateBy.match(/character(s)?/i) && options.TruncateLength <= charCounter && isEndOfWord){
|
|
break;
|
|
}
|
|
if(options.TruncateBy.match(/paragraph(s)?/i) && options.TruncateLength === paragraphCounter){
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!options.StripHTML && tagStack.length > 0){
|
|
while(tagStack.length > 0){
|
|
var tag = tagStack.pop();
|
|
if(tag!=="!--"){
|
|
truncatedText += "</"+tag+">";
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pointer < text.length - 1) {
|
|
if(truncatedText.match(/<\/p>$/gi)){
|
|
truncatedText = truncatedText.replace(/(<\/p>)$/gi, options.Suffix + "$1");
|
|
}else{
|
|
truncatedText = truncatedText + options.Suffix;
|
|
}
|
|
}
|
|
|
|
return truncatedText.trim();
|
|
};
|
|
|
|
// Export to node
|
|
if (typeof module !== 'undefined' && module.exports){
|
|
return module.exports = truncatise;
|
|
}
|
|
|
|
// Nope, export to the browser instead.
|
|
exportTo.truncatise = truncatise;
|
|
}(this));
|