PageSourceSearch

https://moshicom.com/assets/js/trunk8.js

js moshicom.com collected 2026-09-24 10:04:17 UTC 10,074 bytes, 392 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.