PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/ajax/libs/trunk8/1.3.3/trunk8.js

https://gitlab.com/Mirros/cdnjs
JavaScript | 384 lines | 279 code | 55 blank | 50 comment | 57 complexity | 6839946714550f2c636df5120443941d MD5 | raw file
  1. /**!
  2. * trunk8 v1.3.3
  3. * https://github.com/rviscomi/trunk8
  4. *
  5. * Copyright 2012 Rick Viscomi
  6. * Released under the MIT License.
  7. *
  8. * Date: September 26, 2012
  9. */
  10. (function ($) {
  11. var methods,
  12. utils,
  13. SIDES = {
  14. /* cen...ter */
  15. center: 'center',
  16. /* ...left */
  17. left: 'left',
  18. /* right... */
  19. right: 'right'
  20. },
  21. WIDTH = {
  22. auto: 'auto'
  23. };
  24. function trunk8(element) {
  25. this.$element = $(element);
  26. this.original_text = this.$element.html().trim();
  27. this.settings = $.extend({}, $.fn.trunk8.defaults);
  28. }
  29. trunk8.prototype.updateSettings = function (options) {
  30. this.settings = $.extend(this.settings, options);
  31. };
  32. function stripHTML(html) {
  33. var tmp = document.createElement("DIV");
  34. tmp.innerHTML = html;
  35. if (typeof tmp.textContent != 'undefined') {
  36. return tmp.textContent;
  37. }
  38. return tmp.innerText
  39. }
  40. function getHtmlArr(str) {
  41. /* Builds an array of strings and designated */
  42. /* HTML tags around them. */
  43. if (stripHTML(str) === str) {
  44. return str.split(/\s/g);
  45. }
  46. var allResults = [],
  47. reg = /<([a-z]+)([^<]*)(?:>(.*?(?!<\1>)*)<\/\1>|\s+\/>)(['.?!,]*)|((?:[^<>\s])+['.?!,]*\w?|<br\s?\/?>)/ig,
  48. outArr = reg.exec(str),
  49. lastI,
  50. ind;
  51. while (outArr && lastI !== reg.lastIndex) {
  52. lastI = reg.lastIndex;
  53. if (outArr[5]) {
  54. allResults.push(outArr[5]);
  55. } else if (outArr[1]) {
  56. allResults.push({
  57. tag: outArr[1],
  58. attribs: outArr[2],
  59. content: outArr[3],
  60. after: outArr[4]
  61. });
  62. }
  63. outArr = reg.exec(str);
  64. }
  65. for (ind = 0; ind < allResults.length; ind++) {
  66. if (typeof allResults[ind] !== 'string' &&
  67. allResults[ind].content) {
  68. allResults[ind].content = getHtmlArr(allResults[ind].content);
  69. }
  70. }
  71. return allResults;
  72. }
  73. function rebuildHtmlFromBite(bite, htmlObject, fill) {
  74. // Take the processed bite after binary-search
  75. // truncated and re-build the original HTML
  76. // tags around the processed string.
  77. bite = bite.replace(fill, '');
  78. var biteHelper = function(contentArr, tagInfo) {
  79. var retStr = '',
  80. content,
  81. biteContent,
  82. biteLength,
  83. nextWord,
  84. i;
  85. for (i = 0; i < contentArr.length; i++) {
  86. content = contentArr[i];
  87. biteLength = $.trim(bite).split(' ').length;
  88. if ($.trim(bite).length) {
  89. if (typeof content === 'string') {
  90. if (!/<br\s*\/?>/.test(content)) {
  91. if (biteLength === 1 && $.trim(bite).length <= content.length) {
  92. content = bite;
  93. // We want the fill to go inside of the last HTML
  94. // element if the element is a container.
  95. if (tagInfo === 'p' || tagInfo === 'div') {
  96. content += fill;
  97. }
  98. bite = '';
  99. } else {
  100. bite = bite.replace(content, '');
  101. }
  102. }
  103. retStr += $.trim(content) + ((i === contentArr.length-1 || biteLength <= 1) ? '' : ' ');
  104. } else {
  105. biteContent = biteHelper(content.content, content.tag);
  106. if (content.after) bite = bite.replace(content.after, '');
  107. if (biteContent) {
  108. if (!content.after) content.after = ' ';
  109. retStr += '<'+content.tag+content.attribs+'>'+biteContent+'</'+content.tag+'>' + content.after;
  110. }
  111. }
  112. }
  113. }
  114. return retStr;
  115. },
  116. htmlResults = biteHelper(htmlObject);
  117. // Add fill if doesn't exist. This will place it outside the HTML elements.
  118. if (htmlResults.slice(htmlResults.length - fill.length) === fill) {
  119. htmlResults += fill;
  120. }
  121. return htmlResults;
  122. }
  123. function truncate() {
  124. var data = this.data('trunk8'),
  125. settings = data.settings,
  126. width = settings.width,
  127. side = settings.side,
  128. fill = settings.fill,
  129. parseHTML = settings.parseHTML,
  130. line_height = utils.getLineHeight(this) * settings.lines,
  131. str = data.original_text,
  132. length = str.length,
  133. max_bite = '',
  134. lower, upper,
  135. bite_size,
  136. bite,
  137. text,
  138. htmlObject;
  139. /* Reset the field to the original string. */
  140. this.html(str);
  141. text = this.text();
  142. /* If string has HTML and parse HTML is set, build */
  143. /* the data struct to house the tags */
  144. if (parseHTML && stripHTML(str) !== str) {
  145. htmlObject = getHtmlArr(str);
  146. str = stripHTML(str);
  147. length = str.length;
  148. }
  149. if (width === WIDTH.auto) {
  150. /* Assuming there is no "overflow: hidden". */
  151. if (this.height() <= line_height) {
  152. /* Text is already at the optimal trunkage. */
  153. return;
  154. }
  155. /* Binary search technique for finding the optimal trunkage. */
  156. /* Find the maximum bite without overflowing. */
  157. lower = 0;
  158. upper = length - 1;
  159. while (lower <= upper) {
  160. bite_size = lower + ((upper - lower) >> 1);
  161. bite = utils.eatStr(str, side, length - bite_size, fill);
  162. if (parseHTML && htmlObject) {
  163. bite = rebuildHtmlFromBite(bite, htmlObject, fill);
  164. }
  165. this.html(bite);
  166. /* Check for overflow. */
  167. if (this.height() > line_height) {
  168. upper = bite_size - 1;
  169. }
  170. else {
  171. lower = bite_size + 1;
  172. /* Save the bigger bite. */
  173. max_bite = (max_bite.length > bite.length) ? max_bite : bite;
  174. }
  175. }
  176. /* Reset the content to eliminate possible existing scroll bars. */
  177. this.html('');
  178. /* Display the biggest bite. */
  179. this.html(max_bite);
  180. if (settings.tooltip) {
  181. this.attr('title', text);
  182. }
  183. }
  184. else if (!isNaN(width)) {
  185. bite_size = length - width;
  186. bite = utils.eatStr(str, side, bite_size, fill);
  187. this.html(bite);
  188. if (settings.tooltip) {
  189. this.attr('title', str);
  190. }
  191. }
  192. else {
  193. $.error('Invalid width "' + width + '".');
  194. return;
  195. }
  196. settings.onTruncate();
  197. }
  198. methods = {
  199. init: function (options) {
  200. return this.each(function () {
  201. var $this = $(this),
  202. data = $this.data('trunk8');
  203. if (!data) {
  204. $this.data('trunk8', (data = new trunk8(this)));
  205. }
  206. data.updateSettings(options);
  207. truncate.call($this);
  208. });
  209. },
  210. /** Updates the text value of the elements while maintaining truncation. */
  211. update: function (new_string) {
  212. return this.each(function () {
  213. var $this = $(this);
  214. /* Update text. */
  215. if (new_string) {
  216. $this.data('trunk8').original_text = new_string;
  217. }
  218. /* Truncate accordingly. */
  219. truncate.call($this);
  220. });
  221. },
  222. revert: function () {
  223. return this.each(function () {
  224. /* Get original text. */
  225. var text = $(this).data('trunk8').original_text;
  226. /* Revert element to original text. */
  227. $(this).html(text);
  228. });
  229. },
  230. /** Returns this instance's settings object. NOT CHAINABLE. */
  231. getSettings: function () {
  232. return $(this.get(0)).data('trunk8').settings;
  233. }
  234. };
  235. utils = {
  236. /** Replaces [bite_size] [side]-most chars in [str] with [fill]. */
  237. eatStr: function (str, side, bite_size, fill) {
  238. var length = str.length,
  239. key = utils.eatStr.generateKey.apply(null, arguments),
  240. half_length,
  241. half_bite_size;
  242. /* If the result is already in the cache, return it. */
  243. if (utils.eatStr.cache[key]) {
  244. return utils.eatStr.cache[key];
  245. }
  246. /* Common error handling. */
  247. if ((typeof str !== 'string') || (length === 0)) {
  248. $.error('Invalid source string "' + str + '".');
  249. }
  250. if ((bite_size < 0) || (bite_size > length)) {
  251. $.error('Invalid bite size "' + bite_size + '".');
  252. }
  253. else if (bite_size === 0) {
  254. /* No bite should show no truncation. */
  255. return str;
  256. }
  257. if (typeof (fill + '') !== 'string') {
  258. $.error('Fill unable to be converted to a string.');
  259. }
  260. /* Compute the result, store it in the cache, and return it. */
  261. switch (side) {
  262. case SIDES.right:
  263. /* str... */
  264. return utils.eatStr.cache[key] =
  265. $.trim(str.substr(0, length - bite_size)) + fill;
  266. case SIDES.left:
  267. /* ...str */
  268. return utils.eatStr.cache[key] =
  269. fill + $.trim(str.substr(bite_size));
  270. case SIDES.center:
  271. /* Bit-shift to the right by one === Math.floor(x / 2) */
  272. half_length = length >> 1; // halve the length
  273. half_bite_size = bite_size >> 1; // halve the bite_size
  274. /* st...r */
  275. return utils.eatStr.cache[key] =
  276. $.trim(utils.eatStr(str.substr(0, length - half_length), SIDES.right, bite_size - half_bite_size, '')) +
  277. fill +
  278. $.trim(utils.eatStr(str.substr(length - half_length), SIDES.left, half_bite_size, ''));
  279. default:
  280. $.error('Invalid side "' + side + '".');
  281. }
  282. },
  283. getLineHeight: function (elem) {
  284. var floats = $(elem).css('float');
  285. if (floats !== 'none') {
  286. $(elem).css('float', 'none');
  287. }
  288. var pos = $(elem).css('position');
  289. if (pos === 'absolute') {
  290. $(elem).css('position', 'static');
  291. }
  292. var html = $(elem).html(),
  293. wrapper_id = 'line-height-test',
  294. line_height;
  295. /* Set the content to a small single character and wrap. */
  296. $(elem).html('i').wrap('<div id="' + wrapper_id + '" />');
  297. /* Calculate the line height by measuring the wrapper.*/
  298. line_height = $('#' + wrapper_id).innerHeight();
  299. /* Remove the wrapper and reset the content. */
  300. $(elem).html(html).css({ 'float': floats, 'position': pos }).unwrap();
  301. return line_height;
  302. }
  303. };
  304. utils.eatStr.cache = {};
  305. utils.eatStr.generateKey = function () {
  306. return Array.prototype.join.call(arguments, '');
  307. };
  308. $.fn.trunk8 = function (method) {
  309. if (methods[method]) {
  310. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  311. }
  312. else if (typeof method === 'object' || !method) {
  313. return methods.init.apply(this, arguments);
  314. }
  315. else {
  316. $.error('Method ' + method + ' does not exist on jQuery.trunk8');
  317. }
  318. };
  319. /* Default trunk8 settings. */
  320. $.fn.trunk8.defaults = {
  321. fill: '&hellip;',
  322. lines: 1,
  323. side: SIDES.right,
  324. tooltip: true,
  325. width: WIDTH.auto,
  326. parseHTML: false,
  327. onTruncate: function () {}
  328. };
  329. })(jQuery);