PageSourceSearch

https://www.infociments.fr/themes/custom/infociments/js/jquery.dotdotdot.js?v=1

js infociments.fr collected 2026-10-02 05:07:09 UTC 11,730 bytes, 649 lines download raw bytes

1/*
2 *	jQuery dotdotdot 3.2.1
3 *	@requires jQuery 1.7.0 or later
4 *
5 *	dotdotdot.frebsite.nl
6 *
7 *	Copyright (c) Fred Heusschen
8 *	www.frebsite.nl
9 *
10 *	License: CC-BY-NC-4.0
11 *	http://creativecommons.org/licenses/by-nc/4.0/
12 */
13
14(function( $ ) {
15	'use strict';
16	
17	var _PLUGIN_    = 'dotdotdot';
18	var _VERSION_   = '3.2.1';
19
20	if ( $[ _PLUGIN_ ] && $[ _PLUGIN_ ].version > _VERSION_ )
21	{
22		return;
23	}
24
25
26
27	/*
28		The class
29	*/
30	$[ _PLUGIN_ ] = function( $container, opts )
31	{
32		this.$dot 	= $container;
33		this.api	= [ 'getInstance', 'truncate', 'restore', 'destroy', 'watch', 'unwatch' ];
34		this.opts	= opts;
35
36		var oldAPI = this.$dot.data( _PLUGIN_ );
37		if ( oldAPI )
38		{
39			oldAPI.destroy();
40		}
41
42		this.init();
43		this.truncate();
44
45		if ( this.opts.watch )
46		{
47			this.watch();
48		}
49
50		return this;
51	};
52
53	$[ _PLUGIN_ ].version 	= _VERSION_;
54	$[ _PLUGIN_ ].uniqueId 	= 0;
55
56	$[ _PLUGIN_ ].defaults  = {
57		ellipsis		: '\u2026 ',
58		callback		: function( isTruncated ) {},
59		truncate 		: 'word',
60		tolerance		: 0,
61		keep			: null,
62		watch			: 'window',
63		height 			: null
64	};
65
66
67	$[ _PLUGIN_ ].prototype = {
68
69		init: function()
70		{
71			this.watchTimeout		= null;
72			this.watchInterval		= null;
73			this.uniqueId 			= $[ _PLUGIN_ ].uniqueId++;
74			this.originalStyle		= this.$dot.attr( 'style' ) || '';
75			this.originalContent 	= this._getOriginalContent();
76			
77			if ( this.$dot.css( 'word-wrap' ) !== 'break-word' )
78			{
79				this.$dot.css( 'word-wrap', 'break-word' );
80			}
81			if ( this.$dot.css( 'white-space' ) === 'nowrap' )
82			{
83				this.$dot.css( 'white-space', 'normal' );
84			}
85
86			if ( this.opts.height === null )
87			{
88				this.opts.height = this._getMaxHeight();
89			}
90
91			if ( typeof this.opts.ellipsis == 'string' )
92			{
93				this.opts.ellipsis = document.createTextNode( this.opts.ellipsis );
94			}
95		},
96
97		getInstance: function()
98		{
99			return this;
100		},
101
102		truncate: function()
103		{
104			var that = this;
105
106
107			//	Add inner node for measuring the height
108			this.$inner = this.$dot
109				.wrapInner( '<div />' )
110				.children()
111				.css({
112					'display'	: 'block',
113					'height'	: 'auto',
114					'width'		: 'auto',
115					'border'	: 'none',
116					'padding'	: 0,
117					'margin'	: 0
118				});
119
120
121			//	Set original content
122			this.$inner
123				.empty()
124				.append( this.originalContent.clone( true ) );
125
126
127			//	Get max height
128			this.maxHeight = this._getMaxHeight();
129
130
131			//	Truncate the text
132			var isTruncated = !this._fits();
133			this._truncateToNode( this.$inner[ 0 ] );
134
135			this.$dot[ isTruncated ? 'addClass' : 'removeClass' ]( _c.truncated );
136
137
138			//	Remove inner node
139			this.$inner.replaceWith( this.$inner.contents() );
140			this.$inner = null;
141
142
143			//	 Callback
144			this.opts.callback.call( this.$dot[ 0 ], isTruncated );
145
146			return isTruncated;
147		},
148
149		restore: function()
150		{
151			this.unwatch();
152
153			this.$dot
154				.empty()
155				.append( this.originalContent )
156				.attr( 'style', this.originalStyle )
157				.removeClass( _c.truncated );
158		},
159
160		destroy: function()
161		{
162			this.restore();
163			this.$dot.data( _PLUGIN_, null );
164		},
165
166		watch: function()
167		{
168			var that = this;
169
170			this.unwatch();
171
172			var oldSizes = {};
173
174			if ( this.opts.watch == 'window' )
175			{
176				$wndw.on(
177					_e.resize + that.uniqueId,
178					function( e )
179					{
180						if ( that.watchTimeout )
181						{
182							clearTimeout( that.watchTimeout );
183						}
184						that.watchTimeout = setTimeout(
185							function() {
186
187								oldSizes = that._watchSizes( oldSizes, $wndw, 'width', 'height' );
188
189							}, 100
190						);
191					}
192				);
193
194			}
195			else
196			{
197				this.watchInterval = setInterval(
198					function()
199					{
200						oldSizes = that._watchSizes( oldSizes, that.$dot, 'innerWidth', 'innerHeight' );
201
202					}, 500
203				);
204			}
205		},
206
207		unwatch: function()
208		{
209			$wndw.off( _e.resize + this.uniqueId );
210
211			if ( this.watchInterval )
212			{
213				clearInterval( this.watchInterval );
214			}
215
216			if ( this.watchTimeout )
217			{
218				clearTimeout( this.watchTimeout );
219			}
220		},
221
222		_api: function()
223		{
224			var that = this,
225				api = {};
226
227			$.each( this.api,
228				function( i )
229				{
230					var fn = this;
231					api[ fn ] = function()
232					{
233						var re = that[ fn ].apply( that, arguments );
234						return ( typeof re == 'undefined' ) ? api : re;
235					};
236				}
237			);
238			return api;
239		},
240
241		_truncateToNode: function( _elem )
242		{
243
244			var that = this;
245
246			var _coms = [],
247				_elms = [];
248
249			//	Empty the node 
250			//		-> replace all contents with comments
251			$(_elem)
252				.contents()
253				.each(
254					function()
255					{
256						var $e = $(this);
257						if ( !$e.hasClass( _c.keep ) )
258						{
259							var c = document.createComment( '' );
260							$e.replaceWith( c );
261
262							_elms.push( this );
263							_coms.push( c );
264						}
265					}
266				);
267
268			if ( !_elms.length )
269			{
270				return;
271			}
272
273			//	Re-fill the node 
274			//		-> replace comments with contents until it doesn't fit anymore
275			for ( var e = 0; e < _elms.length; e++ )
276			{
277
278				$(_coms[ e ]).replaceWith( _elms[ e ] );
279
280				$(_elms[ e ]).append( this.opts.ellipsis );
281				var fits = this._fits();
282				$(this.opts.ellipsis, _elms[ e ]).remove();
283
284				if ( !fits )
285				{
286					if ( this.opts.truncate == 'node' && e > 1 )
287					{
288						$(_elms[ e - 2 ]).remove();
289						return;
290					}
291					break;
292				}
293			}
294
295			//	Remove left over comments
296			for ( var c = e; c < _coms.length; c++ )
297			{
298				$(_coms[ c ]).remove();
299			}
300
301			//	Get last node 
302			//		-> the node that overflows
303
304			var _last = _elms[ Math.max( 0, Math.min( e, _elms.length - 1 ) ) ];
305
306			//	Border case
307			//		-> the last node with only an ellipsis in it...
308			if ( _last.nodeType == 1 )
309			{
310
311				var $e = $('<' + _last.nodeName + ' />');
312				$e.append( this.opts.ellipsis );
313
314				$(_last).replaceWith( $e );
315
316				//	... fits
317				//		-> Restore the full last node
318				if ( this._fits() )
319				{
320					$e.replaceWith( _last );
321				}
322
323				//	... doesn't fit
324				//		-> remove it and go back one node
325				else
326				{
327					$e.remove();
328					_last = _elms[ Math.max( 0, e - 1 ) ];
329				}
330			}
331
332			//	Proceed inside last node
333			if ( _last.nodeType == 1 )
334			{
335				this._truncateToNode( _last );
336			}
337			else
338			{
339				this._truncateToWord( _last );
340			}
341		},
342
343		_truncateToWord: function( _elem )
344		{
345
346			var e = _elem;
347
348			var that = this;
349
350			var txt = this.__getTextContent( e ),
351				sep = ( txt.indexOf( ' ' ) !== -1 ) ? ' ' : '\u3000',
352				arr = txt.split( sep ),
353				str = '';
354
355			for ( var a = arr.length; a >= 0; a-- )
356			{
357				str = arr.slice( 0, a ).join( sep );
358
359				that.__setTextContent( e, that._addEllipsis( str ) );
360
361				if ( that._fits() )
362				{
363					if ( that.opts.truncate == 'letter' )
364					{
365						that.__setTextContent( e, arr.slice( 0, a + 1 ).join( sep ) );
366						that._truncateToLetter( e );
367					}
368					break;
369				}
370			}
371		},
372
373		_truncateToLetter: function( e )
374		{
375			var that = this;
376
377			var txt = this.__getTextContent( e ),
378				arr = txt.split( '' ),
379				str = '';
380
381			for ( var a = arr.length; a >= 0; a-- )
382			{
383				str = arr.slice( 0, a ).join( '' );
384
385				if ( !str.length )
386				{
387					continue;
388				}
389
390				that.__setTextContent( e, that._addEllipsis( str ) );
391
392				if ( that._fits() )
393				{
394					break;
395				}
396			}
397		},
398
399		_fits: function()
400		{
401			return ( this.$inner.innerHeight() <= this.maxHeight + this.opts.tolerance );
402		},
403
404		_addEllipsis: function( txt )
405		{
406			var remove = [' ', '\u3000', ',', ';', '.', '!', '?'];
407
408			while ( $.inArray( txt.slice( -1 ), remove ) > -1 )
409			{
410				txt = txt.slice( 0, -1 );
411			}
412			txt += this.__getTextContent( this.opts.ellipsis );
413
414			return txt;
415		},
416
417		_getOriginalContent: function()
418		{
419			var that = this;
420
421			//	Add "keep" class to nodes to keep
422			this.$dot
423				.find( 'script, style' )
424				.addClass( _c.keep );
425
426			if ( this.opts.keep )
427			{
428				this.$dot
429					.find( this.opts.keep )
430					.addClass( _c.keep );
431			}
432
433			//	Filter out unneeded whitespace
434			this.$dot
435				.find( '*' )
436				.not( '.' + _c.keep )
437				.add( this.$dot )
438				.contents()
439				.each(
440					function()
441					{
442
443						var e = this,
444							$e = $(this);
445
446						//	Text nodes
447						if ( e.nodeType == 3 )
448						{
449
450							//	Remove whitespace where it does not take up space in the DOM
451							if ( $.trim( that.__getTextContent( e ) ) == '' )
452							{
453								if ( $e.parent().is( 'table, thead, tbody, tfoot, tr, dl, ul, ol, video' ) )
454								{
455									$e.remove();
456									return;
457								}
458								if ( $e.prev().is( 'div, p, table, td, td, dt, dd, li' ) )
459								{
460									$e.remove();
461									return;
462								}
463								if ( $e.next().is( 'div, p, table, td, td, dt, dd, li' ) )
464								{
465									$e.remove();
466									return;
467								}
468								if ( !$e.prev().length )
469								{
470									$e.remove();
471									return;
472								}
473								if ( !$e.next().length )
474								{
475									$e.remove();
476									return;
477								}
478							}
479						}
480
481						//	Comment nodes
482						else if ( e.nodeType == 8 )
483						{
484							$e.remove();
485						}
486
487					}
488				);
489
490			return this.$dot.contents();
491		},
492
493		_getMaxHeight: function()
494		{
495			if ( typeof this.opts.height == 'number' )
496			{
497				return this.opts.height;
498			}
499
500			//	Find smallest CSS height
501			var arr = [ 'maxHeight', 'height' ],
502				hgh = 0;
503 
504			for ( var a = 0; a < arr.length; a++ )
505			{
506				hgh = window.getComputedStyle( this.$dot[ 0 ] )[ arr[ a ] ];
507				if ( hgh.slice( -2 ) == 'px' )
508				{
509					hgh = parseFloat( hgh );
510					break;
511				}
512			}
513
514			//	Remove padding-top/bottom when needed.
515			var arr = [];
516			switch ( this.$dot.css( 'boxSizing' ) )
517			{
518				case 'border-box':
519					arr.push( 'borderTopWidth' );
520					arr.push( 'borderBottomWidth' );
521					//	no break -> padding needs to be added too
522
523				case 'padding-box':
524					arr.push( 'paddingTop' );
525					arr.push( 'paddingBottom' );
526					break;
527			}
528			for ( var a = 0; a < arr.length; a++ )
529			{
530				var p = window.getComputedStyle( this.$dot[ 0 ] )[ arr[ a ] ];
531				if ( p.slice( -2 ) == 'px' )
532				{
533					hgh -= parseFloat( p );
534				}
535			}
536
537			//	Sanitize
538			return Math.max( hgh, 0 );
539		},
540
541		_watchSizes: function( oldSizes, $elem, width, height )
542		{
543			if ( this.$dot.is( ':visible' ) )
544			{
545				var newSizes = {
546					'width'		: $elem[ width  ](),
547					'height'	: $elem[ height ]()
548				};
549
550				if ( oldSizes.width != newSizes.width || oldSizes.height != newSizes.height )
551				{
552					this.truncate();
553				}
554
555				return newSizes;
556			}
557			return oldSizes;
558		},
559
560		__getTextContent: function( elem )
561		{
562			var arr = [ 'nodeValue', 'textContent', 'innerText' ];
563			for ( var a = 0; a < arr.length; a++ )
564			{
565				if ( typeof elem[ arr[ a ] ] == 'string' )
566				{
567					return elem[ arr[ a ] ];
568				}
569			}
570			return '';
571		},
572		__setTextContent: function( elem, content )
573		{
574			var arr = [ 'nodeValue', 'textContent', 'innerText' ];
575			for ( var a = 0; a < arr.length; a++ )
576			{
577				elem[ arr[ a ] ] = content;
578			}
579		}
580	};
581
582
583
584	/*
585		The jQuery plugin
586	*/
587	$.fn[ _PLUGIN_ ] = function( opts )
588	{
589		initPlugin();
590
591		opts = $.extend( true, {}, $[ _PLUGIN_ ].defaults, opts );
592
593		return this.each(
594			function()
595			{
596				$(this).data( _PLUGIN_, new $[ _PLUGIN_ ]( $(this), opts )._api() );
597			}
598		);
599	};
600
601
602
603	/*
604		Global variables
605	*/
606	var _c, _d, _e, $wndw;
607
608	function initPlugin()
609	{
610		$wndw = $(window);
611
612		//	Classnames, Datanames, Eventnames
613		_c = {};
614		_d = {};
615		_e = {};
616
617		$.each( [ _c, _d, _e ],
618			function( i, o )
619			{
620				o.add = function( a )
621				{
622					a = a.split( ' ' );
623					for ( var b = 0, l = a.length; b < l; b++ )
624					{
625						o[ a[ b ] ] = o.ddd( a[ b ] );
626					}
627				};
628			}
629		);
630
631		//	Classnames
632		_c.ddd = function( c ) { return 'ddd-' + c; };
633		_c.add( 'truncated keep' );
634
635		//	Datanames
636		_d.ddd = function( d ) { return 'ddd-' + d; };
637
638		//	Eventnames
639		_e.ddd = function( e ) { return e + '.ddd'; };
640		_e.add( 'resize' );
641
642
643		//	Only once
644		initPlugin = function() {};
645
646	}
647
648
649})( jQuery );

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.