truncate-smart.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * Date: 2015-10-05
  3. * Author: Kasper Søfren <soefritz@gmail.com> (https://github.com/kafoso)
  4. *
  5. * A truncation feature, where the ellipsis will be placed at a section within
  6. * the URL making it still somewhat human readable.
  7. *
  8. * @param {String} url A URL.
  9. * @param {Number} truncateLen The maximum length of the truncated output URL string.
  10. * @param {String} ellipsisChars The characters to place within the url, e.g. "...".
  11. * @return {String} The truncated URL.
  12. */
  13. export function truncateSmart(url, truncateLen, ellipsisChars) {
  14. var ellipsisLengthBeforeParsing;
  15. var ellipsisLength;
  16. if (ellipsisChars == null) {
  17. ellipsisChars = '&hellip;';
  18. ellipsisLength = 3;
  19. ellipsisLengthBeforeParsing = 8;
  20. }
  21. else {
  22. ellipsisLength = ellipsisChars.length;
  23. ellipsisLengthBeforeParsing = ellipsisChars.length;
  24. }
  25. var parse_url = function (url) {
  26. // Functionality inspired by PHP function of same name
  27. var urlObj = {};
  28. var urlSub = url;
  29. var match = urlSub.match(/^([a-z]+):\/\//i);
  30. if (match) {
  31. urlObj.scheme = match[1];
  32. urlSub = urlSub.substr(match[0].length);
  33. }
  34. match = urlSub.match(/^(.*?)(?=(\?|#|\/|$))/i);
  35. if (match) {
  36. urlObj.host = match[1];
  37. urlSub = urlSub.substr(match[0].length);
  38. }
  39. match = urlSub.match(/^\/(.*?)(?=(\?|#|$))/i);
  40. if (match) {
  41. urlObj.path = match[1];
  42. urlSub = urlSub.substr(match[0].length);
  43. }
  44. match = urlSub.match(/^\?(.*?)(?=(#|$))/i);
  45. if (match) {
  46. urlObj.query = match[1];
  47. urlSub = urlSub.substr(match[0].length);
  48. }
  49. match = urlSub.match(/^#(.*?)$/i);
  50. if (match) {
  51. urlObj.fragment = match[1];
  52. //urlSub = urlSub.substr(match[0].length); -- not used. Uncomment if adding another block.
  53. }
  54. return urlObj;
  55. };
  56. var buildUrl = function (urlObj) {
  57. var url = '';
  58. if (urlObj.scheme && urlObj.host) {
  59. url += urlObj.scheme + '://';
  60. }
  61. if (urlObj.host) {
  62. url += urlObj.host;
  63. }
  64. if (urlObj.path) {
  65. url += '/' + urlObj.path;
  66. }
  67. if (urlObj.query) {
  68. url += '?' + urlObj.query;
  69. }
  70. if (urlObj.fragment) {
  71. url += '#' + urlObj.fragment;
  72. }
  73. return url;
  74. };
  75. var buildSegment = function (segment, remainingAvailableLength) {
  76. var remainingAvailableLengthHalf = remainingAvailableLength / 2, startOffset = Math.ceil(remainingAvailableLengthHalf), endOffset = -1 * Math.floor(remainingAvailableLengthHalf), end = '';
  77. if (endOffset < 0) {
  78. end = segment.substr(endOffset);
  79. }
  80. return segment.substr(0, startOffset) + ellipsisChars + end;
  81. };
  82. if (url.length <= truncateLen) {
  83. return url;
  84. }
  85. var availableLength = truncateLen - ellipsisLength;
  86. var urlObj = parse_url(url);
  87. // Clean up the URL
  88. if (urlObj.query) {
  89. var matchQuery = urlObj.query.match(/^(.*?)(?=(\?|\#))(.*?)$/i);
  90. if (matchQuery) {
  91. // Malformed URL; two or more "?". Removed any content behind the 2nd.
  92. urlObj.query = urlObj.query.substr(0, matchQuery[1].length);
  93. url = buildUrl(urlObj);
  94. }
  95. }
  96. if (url.length <= truncateLen) {
  97. return url;
  98. }
  99. if (urlObj.host) {
  100. urlObj.host = urlObj.host.replace(/^www\./, '');
  101. url = buildUrl(urlObj);
  102. }
  103. if (url.length <= truncateLen) {
  104. return url;
  105. }
  106. // Process and build the URL
  107. var str = '';
  108. if (urlObj.host) {
  109. str += urlObj.host;
  110. }
  111. if (str.length >= availableLength) {
  112. if (urlObj.host.length == truncateLen) {
  113. return (urlObj.host.substr(0, truncateLen - ellipsisLength) + ellipsisChars).substr(0, availableLength + ellipsisLengthBeforeParsing);
  114. }
  115. return buildSegment(str, availableLength).substr(0, availableLength + ellipsisLengthBeforeParsing);
  116. }
  117. var pathAndQuery = '';
  118. if (urlObj.path) {
  119. pathAndQuery += '/' + urlObj.path;
  120. }
  121. if (urlObj.query) {
  122. pathAndQuery += '?' + urlObj.query;
  123. }
  124. if (pathAndQuery) {
  125. if ((str + pathAndQuery).length >= availableLength) {
  126. if ((str + pathAndQuery).length == truncateLen) {
  127. return (str + pathAndQuery).substr(0, truncateLen);
  128. }
  129. var remainingAvailableLength = availableLength - str.length;
  130. return (str + buildSegment(pathAndQuery, remainingAvailableLength)).substr(0, availableLength + ellipsisLengthBeforeParsing);
  131. }
  132. else {
  133. str += pathAndQuery;
  134. }
  135. }
  136. if (urlObj.fragment) {
  137. var fragment = '#' + urlObj.fragment;
  138. if ((str + fragment).length >= availableLength) {
  139. if ((str + fragment).length == truncateLen) {
  140. return (str + fragment).substr(0, truncateLen);
  141. }
  142. var remainingAvailableLength2 = availableLength - str.length;
  143. return (str + buildSegment(fragment, remainingAvailableLength2)).substr(0, availableLength + ellipsisLengthBeforeParsing);
  144. }
  145. else {
  146. str += fragment;
  147. }
  148. }
  149. if (urlObj.scheme && urlObj.host) {
  150. var scheme = urlObj.scheme + '://';
  151. if ((str + scheme).length < availableLength) {
  152. return (scheme + str).substr(0, truncateLen);
  153. }
  154. }
  155. if (str.length <= truncateLen) {
  156. return str;
  157. }
  158. var end = '';
  159. if (availableLength > 0) {
  160. end = str.substr(-1 * Math.floor(availableLength / 2));
  161. }
  162. return (str.substr(0, Math.ceil(availableLength / 2)) + ellipsisChars + end).substr(0, availableLength + ellipsisLengthBeforeParsing);
  163. }
  164. //# sourceMappingURL=truncate-smart.js.map