/* https://github.com/pathable/truncate */

(function ($) {

	// Matches trailing non-space characters.
	var chop = /(\s*\S+|\s)$/;

	// Matches the first word in the string.
	var start = /^(\S*)/;

	// Return a truncated html string.  Delegates to $.fn.truncate.
	$.truncate = function (html, options) {
		return $('<div></div>').append(html).truncate(options).html();
	};

	// Truncate the contents of an element in place.
	$.fn.truncate = function (options) {
		if ($.isNumeric(options)) options = { length: options };
		var o = $.extend({}, $.truncate.defaults, options);

		return this.each(function () {
			var self = $(this);

			if (o.noBreaks) self.find('br').replaceWith(' ');

			var text = self.text();
			var excess = text.length - o.length;

			if (o.stripTags) self.text(text);

			// Chop off any partial words if appropriate.
			if (o.words && excess > 0) {
				var truncated = text.slice(0, o.length).replace(chop, '').length;

				if (o.keepFirstWord && truncated === 0) {
					excess = text.length - start.exec(text)[0].length - 1;
				} else {
					excess = text.length - truncated - 1;
				}
			}

			if (excess < 0 || !excess && !o.truncated) return;

			// Iterate over each child node in reverse, removing excess text.
			$.each(self.contents().get().reverse(), function (i, el) {
				var $el = $(el);
				var text = $el.text();
				var length = text.length;

				// If the text is longer than the excess, remove the node and continue.
				if (length <= excess) {
					o.truncated = true;
					excess -= length;
					$el.remove();
					return;
				}

				// Remove the excess text and append the ellipsis.
				if (el.nodeType === 3) {
					$(el.splitText(length - excess - 1)).replaceWith(o.ellipsis);
					return false;
				}

				// Recursively truncate child nodes.
				$el.truncate($.extend(o, { length: length - excess }));
				return false;
			});
		});
	};

	$.truncate.defaults = {

		// Strip all html elements, leaving only plain text.
		stripTags: false,

		// Only truncate at word boundaries.
		words: false,

		// When 'words' is active, keeps the first word in the string
		// even if it's longer than a target length.
		keepFirstWord: false,

		// Replace instances of <br> with a single space.
		noBreaks: false,

		// The maximum length of the truncated html.
		length: Infinity,

		// The character to use as the ellipsis.  The word joiner (U+2060) can be
		// used to prevent a hanging ellipsis, but displays incorrectly in Chrome
		// on Windows 7.
		// http://code.google.com/p/chromium/issues/detail?id=68323
		ellipsis: '\u2026' // '\u2060\u2026'

	};

})(jQuery);
