Completed
Push — master ( e6718f...1f82f0 )
by Chad
18s queued 16s
created

jquery.dotdotdot-1.5.9.js ➔ children   F

Complexity

Conditions 40

Size

Total Lines 31
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 40
eloc 21
c 0
b 0
f 0
dl 0
loc 31
rs 0

How to fix   Complexity   

Complexity

Complex classes like jquery.dotdotdot-1.5.9.js ➔ children often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*	
2
 *	jQuery dotdotdot 1.5.9
3
 *	
4
 *	Copyright (c) 2013 Fred Heusschen
5
 *	www.frebsite.nl
6
 *
7
 *	Plugin website:
8
 *	dotdotdot.frebsite.nl
9
 *
10
 *	Dual licensed under the MIT and GPL licenses.
11
 *	http://en.wikipedia.org/wiki/MIT_License
12
 *	http://en.wikipedia.org/wiki/GNU_General_Public_License
13
 */
14
15
(function( $ )
16
{
17
	if ( $.fn.dotdotdot )
18
	{
19
		return;
20
	}
21
22
	$.fn.dotdotdot = function( o )
23
	{
24
		if ( this.length == 0 )
0 ignored issues
show
Best Practice introduced by
Comparing this.length to 0 using the == operator is not safe. Consider using === instead.
Loading history...
25
		{
26
			if ( !o || o.debug !== false )
27
			{
28
				debug( true, 'No element found for "' + this.selector + '".' );				
29
			}
30
			return this;
31
		}
32
		if ( this.length > 1 )
33
		{
34
			return this.each(
35
				function()
36
				{
37
					$(this).dotdotdot( o );
38
				}
39
			);
40
		}
41
42
43
		var $dot = this;
44
45
		if ( $dot.data( 'dotdotdot' ) )
46
		{
47
			$dot.trigger( 'destroy.dot' );
48
		}
49
50
		$dot.data( 'dotdotdot-style', $dot.attr( 'style' ) );
51
		$dot.css( 'word-wrap', 'break-word' );
52
53
		$dot.bind_events = function()
54
		{
55
			$dot.bind(
56
				'update.dot',
57
				function( e, c )
58
				{
59
					e.preventDefault();
60
					e.stopPropagation();
61
62
					opts.maxHeight = ( typeof opts.height == 'number' ) 
63
						? opts.height 
64
						: getTrueInnerHeight( $dot );
65
66
					opts.maxHeight += opts.tolerance;
67
68
					if ( typeof c != 'undefined' )
69
					{
70
						if ( typeof c == 'string' || c instanceof HTMLElement )
0 ignored issues
show
Bug introduced by
The variable HTMLElement seems to be never declared. If this is a global, consider adding a /** global: HTMLElement */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
71
						{
72
					 		c = $('<div />').append( c ).contents();
73
						}
74
						if ( c instanceof $ )
75
						{
76
							orgContent = c;
77
						}
78
					}
79
80
					$inr = $dot.wrapInner( '<div class="dotdotdot" />' ).children();
81
					$inr.empty()
82
						.append( orgContent.clone( true ) )
0 ignored issues
show
Bug introduced by
The variable orgContent seems to not be initialized for all possible execution paths.
Loading history...
83
						.css({
84
							'height'	: 'auto',
85
							'width'		: 'auto',
86
							'border'	: 'none',
87
							'padding'	: 0,
88
							'margin'	: 0
89
						});
90
91
					var after = false,
92
						trunc = false;
93
94
					if ( conf.afterElement )
95
					{
96
						after = conf.afterElement.clone( true );
97
						conf.afterElement.remove();
98
					}
99
					if ( test( $inr, opts ) )
100
					{
101
						if ( opts.wrap == 'children' )
102
						{
103
							trunc = children( $inr, opts, after );
104
						}
105
						else
106
						{
107
							trunc = ellipsis( $inr, $dot, $inr, opts, after );
108
						}
109
					}
110
					$inr.replaceWith( $inr.contents() );
111
					$inr = null;
112
					
113
					if ( $.isFunction( opts.callback ) )
114
					{
115
						opts.callback.call( $dot[ 0 ], trunc, orgContent );
116
					}
117
118
					conf.isTruncated = trunc;
119
					return trunc;
120
				}
121
122
			).bind(
123
				'isTruncated.dot',
124
				function( e, fn )
125
				{
126
					e.preventDefault();
127
					e.stopPropagation();
128
129
					if ( typeof fn == 'function' )
130
					{
131
						fn.call( $dot[ 0 ], conf.isTruncated );
132
					}
133
					return conf.isTruncated;
134
				}
135
136
			).bind(
137
				'originalContent.dot',
138
				function( e, fn )
139
				{
140
					e.preventDefault();
141
					e.stopPropagation();
142
143
					if ( typeof fn == 'function' )
144
					{
145
						fn.call( $dot[ 0 ], orgContent );
146
					}
147
					return orgContent;
148
				}
149
150
			).bind(
151
				'destroy.dot',
152
				function( e )
153
				{
154
					e.preventDefault();
155
					e.stopPropagation();
156
157
					$dot.unwatch()
158
						.unbind_events()
159
						.empty()
160
						.append( orgContent )
161
						.attr( 'style', $dot.data( 'dotdotdot-style' ) )
162
						.data( 'dotdotdot', false );
163
				}
164
			);
165
			return $dot;
166
		};	//	/bind_events
167
168
		$dot.unbind_events = function()
169
		{
170
			$dot.unbind('.dot');
171
			return $dot;
172
		};	//	/unbind_events
173
174
		$dot.watch = function()
175
		{
176
			$dot.unwatch();
177
			if ( opts.watch == 'window' )
178
			{
179
				var $window = $(window),
180
					_wWidth = $window.width(),
181
					_wHeight = $window.height(); 
182
183
				$window.bind(
184
					'resize.dot' + conf.dotId,
185
					function()
186
					{
187
						if ( _wWidth != $window.width() || _wHeight != $window.height() || !opts.windowResizeFix )
188
						{
189
							_wWidth = $window.width();
190
							_wHeight = $window.height();
191
	
192
							if ( watchInt )
193
							{
194
								clearInterval( watchInt );
195
							}
196
							watchInt = setTimeout(
197
								function()
198
								{
199
									$dot.trigger( 'update.dot' );
200
								}, 10
201
							);
202
						}
203
					}
204
				);
205
			}
206
			else
207
			{
208
				watchOrg = getSizes( $dot );
209
				watchInt = setInterval(
210
					function()
211
					{
212
						var watchNew = getSizes( $dot );
213
						if ( watchOrg.width  != watchNew.width ||
214
							 watchOrg.height != watchNew.height )
215
						{
216
							$dot.trigger( 'update.dot' );
217
							watchOrg = getSizes( $dot );
218
						}
219
					}, 100
220
				);
221
			}
222
			return $dot;
223
		};
224
		$dot.unwatch = function()
225
		{
226
			$(window).unbind( 'resize.dot' + conf.dotId );
227
			if ( watchInt )
228
			{
229
				clearInterval( watchInt );
230
			}
231
			return $dot;
232
		};
233
234
		var	orgContent	= $dot.contents(),
235
			opts 		= $.extend( true, {}, $.fn.dotdotdot.defaults, o ),
236
			conf		= {},
237
			watchOrg	= {},
238
			watchInt	= null,
239
			$inr		= null;
240
241
		conf.afterElement	= getElement( opts.after, $dot );
242
		conf.isTruncated	= false;
243
		conf.dotId			= dotId++;
244
245
246
		$dot.data( 'dotdotdot', true )
247
			.bind_events()
248
			.trigger( 'update.dot' );
249
250
		if ( opts.watch )
251
		{
252
			$dot.watch();
253
		}
254
255
		return $dot;
256
	};
257
258
259
	//	public
260
	$.fn.dotdotdot.defaults = {
261
		'ellipsis'	: '... ',
262
		'wrap'		: 'word',
263
		'lastCharacter': {
264
			'remove'		: [ ' ', ',', ';', '.', '!', '?' ],
265
			'noEllipsis'	: []
266
		},
267
		'tolerance'	: 0,
268
		'callback'	: null,
269
		'after'		: null,
270
		'height'	: null,
271
		'watch'		: false,
272
		'windowResizeFix': true,
273
		'debug'		: false
274
	};
275
	
276
277
	//	private
278
	var dotId = 1;
279
280
	function children( $elem, o, after )
281
	{
282
		var $elements 	= $elem.children(),
283
			isTruncated	= false;
284
285
		$elem.empty();
286
287
		for ( var a = 0, l = $elements.length; a < l; a++ )
288
		{
289
			var $e = $elements.eq( a );
290
			$elem.append( $e );
291
			if ( after )
292
			{
293
				$elem.append( after );
294
			}
295
			if ( test( $elem, o ) )
296
			{
297
				$e.remove();
298
				isTruncated = true;
299
				break;
300
			}
301
			else
302
			{
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
303
				if ( after )
304
				{
305
					after.remove();
306
				}
307
			}
308
		}
309
		return isTruncated;
310
	}
311
	function ellipsis( $elem, $d, $i, o, after )
312
	{
313
		var $elements 	= $elem.contents(),
314
			isTruncated	= false;
315
316
		$elem.empty();
317
318
		var notx = 'table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, select, optgroup, option, textarea, script, style';
319
		for ( var a = 0, l = $elements.length; a < l; a++ )
320
		{
321
322
			if ( isTruncated )
323
			{
324
				break;
325
			}
326
327
			var e	= $elements[ a ],
328
				$e	= $(e);
329
330
			if ( typeof e == 'undefined' )
331
			{
332
				continue;
333
			}
334
335
			$elem.append( $e );
336
			if ( after )
337
			{
338
				$elem[ ( $elem.is( notx ) ) ? 'after' : 'append' ]( after );
339
			}
340
			if ( e.nodeType == 3 )
341
			{
342
				if ( test( $i, o ) )
343
				{
344
					isTruncated = ellipsisElement( $e, $d, $i, o, after );
345
				}
346
			}
347
			else
348
			{
349
				isTruncated = ellipsis( $e, $d, $i, o, after );
350
			}
351
352
			if ( !isTruncated )
353
			{
354
				if ( after )
355
				{
356
					after.remove();
357
				}
358
			}
359
		}
360
		return isTruncated;
361
	}
362
	function ellipsisElement( $e, $d, $i, o, after )
363
	{
364
		var isTruncated	= false,
365
			e = $e[ 0 ];
366
367
		if ( typeof e == 'undefined' )
368
		{
369
			return false;
370
		}
371
372
		var seporator	= ( o.wrap == 'letter' ) ? '' : ' ',
373
			textArr		= getTextContent( e ).split( seporator ),
374
			position 	= -1,
375
			midPos		= -1,
376
			startPos	= 0,
377
			endPos		= textArr.length - 1;
378
379
		while ( startPos <= endPos )
380
		{
381
			var m = Math.floor( ( startPos + endPos ) / 2 );
382
			if ( m == midPos ) 
383
			{
384
				break;
385
			}
386
			midPos = m;
387
388
			setTextContent( e, textArr.slice( 0, midPos + 1 ).join( seporator ) + o.ellipsis );
389
390
			if ( !test( $i, o ) )
391
			{
392
				position = midPos;
393
				startPos = midPos; 
394
			}
395
			else
396
			{
397
				endPos = midPos;
398
			}				
399
		}	
400
	
401
		if ( position != -1 && !( textArr.length == 1 && textArr[ 0 ].length == 0 ) )
0 ignored issues
show
Best Practice introduced by
Comparing textArr.0.length to 0 using the == operator is not safe. Consider using === instead.
Loading history...
Best Practice introduced by
Comparing textArr.length to 1 using the == operator is not safe. Consider using === instead.
Loading history...
402
		{
403
			var txt = addEllipsis( textArr.slice( 0, position + 1 ).join( seporator ), o );
404
			isTruncated = true;
405
			setTextContent( e, txt );
406
		}
407
		else
408
		{
409
			var $w = $e.parent();
410
			$e.remove();
411
412
			var afterLength = ( after ) ? after.length : 0 ;
413
414
			if ( $w.contents().size() > afterLength )
415
			{
416
				var $n = $w.contents().eq( -1 - afterLength );
417
				isTruncated = ellipsisElement( $n, $d, $i, o, after );
418
			}
419
			else
420
			{
421
				var $p = $w.prev()
422
				var e = $p.contents().eq( -1 )[ 0 ];
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable e already seems to be declared on line 365. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
423
424
				if ( typeof e != 'undefined' )
425
				{
426
					var txt = addEllipsis( getTextContent( e ), o );
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable txt already seems to be declared on line 403. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
427
					setTextContent( e, txt );
428
					if ( after )
429
					{
430
						$p.append( after );
431
					}
432
					$w.remove();
433
					isTruncated = true;
434
				}
435
436
			}
437
		}
438
439
		return isTruncated;
440
	}
441
	function test( $i, o )
442
	{
443
		return $i.innerHeight() > o.maxHeight;
444
	}
445
	function addEllipsis( txt, o )
446
	{
447
		while( $.inArray( txt.slice( -1 ), o.lastCharacter.remove ) > -1 )
448
		{
449
			txt = txt.slice( 0, -1 );
450
		}
451
		if ( $.inArray( txt.slice( -1 ), o.lastCharacter.noEllipsis ) < 0 )
452
		{
453
			txt += o.ellipsis;
454
		}
455
		return txt;
456
	}
457
	function getSizes( $d )
458
	{
459
		return {
460
			'width'	: $d.innerWidth(),
461
			'height': $d.innerHeight()
462
		};
463
	}
464
	function setTextContent( e, content )
465
	{
466
		if ( e.innerText )
467
		{
468
			e.innerText = content;
469
		}
470
		else if ( e.nodeValue )
471
		{
472
			e.nodeValue = content;
473
		}
474
		else if (e.textContent)
475
		{
476
			e.textContent = content;
477
		}
478
479
	}
480
	function getTextContent( e )
481
	{
482
		if ( e.innerText )
483
		{
484
			return e.innerText;
485
		}
486
		else if ( e.nodeValue )
487
		{
488
			return e.nodeValue;
489
		}
490
		else if ( e.textContent )
491
		{
492
			return e.textContent;
493
		}
494
		else
495
		{
496
			return "";
497
		}
498
	}
499
	function getElement( e, $i )
500
	{
501
		if ( typeof e == 'undefined' )
502
		{
503
			return false;
504
		}
505
		if ( !e )
506
		{
507
			return false;
508
		}
509
		if ( typeof e == 'string' )
510
		{
511
			e = $(e, $i);
512
			return ( e.length )
513
				? e 
514
				: false;
515
		}
516
		if ( typeof e == 'object' )
517
		{
518
			return ( typeof e.jquery == 'undefined' )
519
				? false
520
				: e;
521
		}
522
		return false;
523
	}
524
	function getTrueInnerHeight( $el )
525
	{
526
		var h = $el.innerHeight(),
527
			a = [ 'paddingTop', 'paddingBottom' ];
528
529
		for ( var z = 0, l = a.length; z < l; z++ ) {
530
			var m = parseInt( $el.css( a[ z ] ), 10 );
531
			if ( isNaN( m ) )
532
			{
533
				m = 0;
534
			}
535
			h -= m;
536
		}
537
		return h;
538
	}
539
	function debug( d, m )
540
	{
541
		if ( !d )
542
		{
543
			return false;
544
		}
545
		if ( typeof m == 'string' )
546
		{
547
			m = 'dotdotdot: ' + m;
548
		}
549
		else
550
		{
551
			m = [ 'dotdotdot:', m ];
552
		}
553
554
		if ( typeof window.console != 'undefined' )
555
		{
556
			if ( typeof window.console.log != 'undefined' )
557
			{
558
				window.console.log( m );
559
			}
560
		}
561
		return false;
562
	}
563
	
564
565
	//	override jQuery.html
566
	var _orgHtml = $.fn.html;
567
    $.fn.html = function( str ) {
568
		if ( typeof str != 'undefined' )
569
		{
570
			if ( this.data( 'dotdotdot' ) )
571
			{
572
				if ( typeof str != 'function' )
573
				{
574
					return this.trigger( 'update', [ str ] );
575
				}
576
			}
577
			return _orgHtml.call( this, str );
578
		}
579
		return _orgHtml.call( this );
580
    };
581
582
583
	//	override jQuery.text
584
	var _orgText = $.fn.text;
585
    $.fn.text = function( str ) {
586
		if ( typeof str != 'undefined' )
587
		{
588
			if ( this.data( 'dotdotdot' ) )
589
			{
590
				var temp = $( '<div />' );
591
				temp.text( str );
592
				str = temp.html();
593
				temp.remove();
594
				return this.trigger( 'update', [ str ] );
595
			}
596
			return _orgText.call( this, str );
597
		}
598
        return _orgText.call( this );
599
    };
600
601
602
})( jQuery );
603