<commit_before>/**
 *	Angular directive to truncate multi-line text to visible height
 *
 *	@param bind (angular bound value to append) REQUIRED
 *	@param ellipsisAppend (string) string to append at end of truncated text after ellipsis, can be HTML OPTIONAL
 *	@param ellipsisAppendClick (function) function to call if ellipsisAppend is clicked (ellipsisAppend must be clicked) OPTIONAL
 *	@param ellipsisSymbol (string) string to use as ellipsis, replaces default '...' OPTIONAL
 *	@param ellipsisSeparator (string) separator to split string, replaces default ' ' OPTIONAL
 *
 *	@example <p data-ellipsis data-ng-bind="boundData"></p>
 *	@example <p data-ellipsis data-ng-bind="boundData" data-ellipsis-symbol="---"></p>
 *	@example <p data-ellipsis data-ng-bind="boundData" data-ellipsis-append="read more"></p>
 *	@example <p data-ellipsis data-ng-bind="boundData" data-ellipsis-append="read more" data-ellipsis-append-click="displayFull()"></p>
 *
 */
angular.module('dibari.angular-ellipsis',[])

.directive('ellipsis', ['$timeout', '$window', function($timeout, $window) {

	var AsyncDigest = function(delay) {
		var timeout = null;
		var queue = [];

		this.remove = function(fn) {
			if (queue.indexOf(fn) !== -1) {
				queue.splice(queue.indexOf(fn), 1);
				if (queue.length === 0) {
					$timeout.cancel(timeout);
					timeout = null;
				}
			}
		};
		this.add = function(fn) {
			if (queue.indexOf(fn) === -1) {
				queue.push(fn);
			}
			if(!timeout) {
				timeout = $timeout(function() {
					var copy = queue.slice();
					timeout = null;
					// reset scheduled array first in case one of the functions throws an error
					queue.length = 0;
					copy.forEach(function(fn) {
						fn();
					});
				}, delay);
			}
		};
	};

	var asyncDigestImmediate = new AsyncDigest(0);
	var asyncDigestDebounced = new AsyncDigest(75);

	return {
		restrict	: 'A',
		scope		: {
			ngBind				: '=',
			ngBindHtml			: '=',
			ellipsisAppend		: '@',
			ellipsisAppendClick	: '&',
			ellipsisSymbol		: '@',
			ellipsisSeparator	: '@',
			useParent			: "@",
			ellipsisSeparatorReg: '='
		},
		compile : function(elem, attr, linker) {

			return function(scope, element, attributes) {
				/* Window Resize Variables */
					attributes.lastWindowResizeTime = 0;
					attributes.lastWindowResizeWidth = 0;
					attributes.lastWindowResizeHeight = 0;
					attributes.lastWindowTimeoutEvent = null;
				/* State Variables */
					attributes.isTruncated = false;
				function getParentHeight(element){
					var heightOfChildren = 0;
					angular.forEach(element.parent().children(), function(child){
						if(child!=element[0]){
							heightOfChildren += child.clientHeight;
						}
					});
					return element.parent()[0].clientHeight - heightOfChildren;
				}
				function buildEllipsis() {
					var binding = scope.ngBind || scope.ngBindHtml;
					if (binding) {
						var i = 0,
							ellipsisSymbol = (typeof(attributes.ellipsisSymbol) !== 'undefined') ? attributes.ellipsisSymbol : '&hellip;',
							ellipsisSeparator = (typeof(scope.ellipsisSeparator) !== 'undefined') ? attributes.ellipsisSeparator  : ' ',
							ellipsisSeparatorReg =  (typeof(scope.ellipsisSeparatorReg) !== 'undefined') ? scope.ellipsisSeparatorReg : false,
							appendString = (typeof(scope.ellipsisAppend) !== 'undefined' && scope.ellipsisAppend !== '') ? ellipsisSymbol + '<span>' + scope.ellipsisAppend + '</span>' : ellipsisSymbol,
							bindArray = ellipsisSeparatorReg ? binding.match(ellipsisSeparatorReg) : binding.split(ellipsisSeparator);

						attributes.isTruncated = false;
						element.html(binding);<commit_msg>Include check for trusted value<commit_after>/**
 *	Angular directive to truncate multi-line text to visible height
 *
 *	@param bind (angular bound value to append) REQUIRED
 *	@param ellipsisAppend (string) string to append at end of truncated text after ellipsis, can be HTML OPTIONAL
 *	@param ellipsisAppendClick (function) function to call if ellipsisAppend is clicked (ellipsisAppend must be clicked) OPTIONAL
 *	@param ellipsisSymbol (string) string to use as ellipsis, replaces default '...' OPTIONAL
 *	@param ellipsisSeparator (string) separator to split string, replaces default ' ' OPTIONAL
 *
 *	@example <p data-ellipsis data-ng-bind="boundData"></p>
 *	@example <p data-ellipsis data-ng-bind="boundData" data-ellipsis-symbol="---"></p>
 *	@example <p data-ellipsis data-ng-bind="boundData" data-ellipsis-append="read more"></p>
 *	@example <p data-ellipsis data-ng-bind="boundData" data-ellipsis-append="read more" data-ellipsis-append-click="displayFull()"></p>
 *
 */
angular.module('dibari.angular-ellipsis',[])

.directive('ellipsis', ['$timeout', '$window', function($timeout, $window) {

	var AsyncDigest = function(delay) {
		var timeout = null;
		var queue = [];

		this.remove = function(fn) {
			if (queue.indexOf(fn) !== -1) {
				queue.splice(queue.indexOf(fn), 1);
				if (queue.length === 0) {
					$timeout.cancel(timeout);
					timeout = null;
				}
			}
		};
		this.add = function(fn) {
			if (queue.indexOf(fn) === -1) {
				queue.push(fn);
			}
			if(!timeout) {
				timeout = $timeout(function() {
					var copy = queue.slice();
					timeout = null;
					// reset scheduled array first in case one of the functions throws an error
					queue.length = 0;
					copy.forEach(function(fn) {
						fn();
					});
				}, delay);
			}
		};
	};

	var asyncDigestImmediate = new AsyncDigest(0);
	var asyncDigestDebounced = new AsyncDigest(75);

	return {
		restrict	: 'A',
		scope		: {
			ngBind				: '=',
			ngBindHtml			: '=',
			ellipsisAppend		: '@',
			ellipsisAppendClick	: '&',
			ellipsisSymbol		: '@',
			ellipsisSeparator	: '@',
			useParent			: "@",
			ellipsisSeparatorReg: '='
		},
		compile : function(elem, attr, linker) {

			return function(scope, element, attributes) {
				/* Window Resize Variables */
					attributes.lastWindowResizeTime = 0;
					attributes.lastWindowResizeWidth = 0;
					attributes.lastWindowResizeHeight = 0;
					attributes.lastWindowTimeoutEvent = null;
				/* State Variables */
					attributes.isTruncated = false;
				function getParentHeight(element){
					var heightOfChildren = 0;
					angular.forEach(element.parent().children(), function(child){
						if(child!=element[0]){
							heightOfChildren += child.clientHeight;
						}
					});
					return element.parent()[0].clientHeight - heightOfChildren;
				}
				function buildEllipsis() {
					var binding = scope.ngBind || scope.ngBindHtml;
					if(binding.$$unwrapTrustedValue()) {
						binding = binding.$$unwrapTrustedValue();
					}
					if (binding) {
						var i = 0,
							ellipsisSymbol = (typeof(attributes.ellipsisSymbol) !== 'undefined') ? attributes.ellipsisSymbol : '&hellip;',
							ellipsisSeparator = (typeof(scope.ellipsisSeparator) !== 'undefined') ? attributes.ellipsisSeparator  : ' ',
							ellipsisSeparatorReg =  (typeof(scope.ellipsisSeparatorReg) !== 'undefined') ? scope.ellipsisSeparatorReg : false,
							appendString = (typeof(scope.ellipsisAppend) !== 'undefined' && scope.ellipsisAppend !== '') ? ellipsisSymbol + '<span>' + scope.ellipsisAppend + '</span>' : ellipsisSymbol,
							bindArray = ellipsisSeparatorReg ? binding.match(ellipsisSeparatorReg) : binding.split(ellipsisSeparator);

						attributes.isTruncated = false;
						element.html(binding);
{'fraction_non_alphanumeric': 0.1423312883435583, 'fraction_numerical': 0.00408997955010225, 'mean_word_length': 3.628391167192429, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7023114', 'n_tokens_mistral': 2796, 'n_tokens_neox': 2324, 'n_words': 504}