]> git.immae.eu Git - github/wallabag/wallabag.git/blame - src/Wallabag/CoreBundle/Resources/public/themes/material/js/jquery.dotdotdot.js
Simplify the initialization of the plugin dotdotdot
[github/wallabag/wallabag.git] / src / Wallabag / CoreBundle / Resources / public / themes / material / js / jquery.dotdotdot.js
CommitLineData
e32aea53
AD
1/*
2 * jQuery dotdotdot 1.8.3
3 *
4 * Copyright (c) Fred Heusschen
5 * www.frebsite.nl
6 *
7 * Plugin website:
8 * dotdotdot.frebsite.nl
9 *
10 * Licensed under the MIT license.
11 * http://en.wikipedia.org/wiki/MIT_License
12 */
13
14(function( $, undef )
15{
16 if ( $.fn.dotdotdot )
17 {
18 return;
19 }
20
21 $.fn.dotdotdot = function( o )
22 {
23 if ( this.length == 0 )
24 {
25 $.fn.dotdotdot.debug( 'No element found for "' + this.selector + '".' );
26 return this;
27 }
28 if ( this.length > 1 )
29 {
30 return this.each(
31 function()
32 {
33 $(this).dotdotdot( o );
34 }
35 );
36 }
37
38
39 var $dot = this;
40 var orgContent = $dot.contents();
41
42 if ( $dot.data( 'dotdotdot' ) )
43 {
44 $dot.trigger( 'destroy.dot' );
45 }
46
47 $dot.data( 'dotdotdot-style', $dot.attr( 'style' ) || '' );
48 $dot.css( 'word-wrap', 'break-word' );
49 if ($dot.css( 'white-space' ) === 'nowrap')
50 {
51 $dot.css( 'white-space', 'normal' );
52 }
53
54 $dot.bind_events = function()
55 {
56 $dot.bind(
57 'update.dot',
58 function( e, c )
59 {
60 $dot.removeClass("is-truncated");
61 e.preventDefault();
62 e.stopPropagation();
63
64 switch( typeof opts.height )
65 {
66 case 'number':
67 opts.maxHeight = opts.height;
68 break;
69
70 case 'function':
71 opts.maxHeight = opts.height.call( $dot[ 0 ] );
72 break;
73
74 default:
75 opts.maxHeight = getTrueInnerHeight( $dot );
76 break;
77 }
78
79 opts.maxHeight += opts.tolerance;
80
81 if ( typeof c != 'undefined' )
82 {
83 if ( typeof c == 'string' || ('nodeType' in c && c.nodeType === 1) )
84 {
85 c = $('<div />').append( c ).contents();
86 }
87 if ( c instanceof $ )
88 {
89 orgContent = c;
90 }
91 }
92
93 $inr = $dot.wrapInner( '<div class="dotdotdot" />' ).children();
94 $inr.contents()
95 .detach()
96 .end()
97 .append( orgContent.clone( true ) )
98 .find( 'br' )
99 .replaceWith( ' <br /> ' )
100 .end()
101 .css({
102 'height' : 'auto',
103 'width' : 'auto',
104 'border' : 'none',
105 'padding' : 0,
106 'margin' : 0
107 });
108
109 var after = false,
110 trunc = false;
111
112 if ( conf.afterElement )
113 {
114 after = conf.afterElement.clone( true );
115 after.show();
116 conf.afterElement.detach();
117 }
118
119 if ( test( $inr, opts ) )
120 {
121 if ( opts.wrap == 'children' )
122 {
123 trunc = children( $inr, opts, after );
124 }
125 else
126 {
127 trunc = ellipsis( $inr, $dot, $inr, opts, after );
128 }
129 }
130 $inr.replaceWith( $inr.contents() );
131 $inr = null;
132
133 if ( $.isFunction( opts.callback ) )
134 {
135 opts.callback.call( $dot[ 0 ], trunc, orgContent );
136 }
137
138 conf.isTruncated = trunc;
139 return trunc;
140 }
141
142 ).bind(
143 'isTruncated.dot',
144 function( e, fn )
145 {
146 e.preventDefault();
147 e.stopPropagation();
148
149 if ( typeof fn == 'function' )
150 {
151 fn.call( $dot[ 0 ], conf.isTruncated );
152 }
153 return conf.isTruncated;
154 }
155
156 ).bind(
157 'originalContent.dot',
158 function( e, fn )
159 {
160 e.preventDefault();
161 e.stopPropagation();
162
163 if ( typeof fn == 'function' )
164 {
165 fn.call( $dot[ 0 ], orgContent );
166 }
167 return orgContent;
168 }
169
170 ).bind(
171 'destroy.dot',
172 function( e )
173 {
174 e.preventDefault();
175 e.stopPropagation();
176
177 $dot.unwatch()
178 .unbind_events()
179 .contents()
180 .detach()
181 .end()
182 .append( orgContent )
183 .attr( 'style', $dot.data( 'dotdotdot-style' ) || '' )
184 .removeClass( 'is-truncated' )
185 .data( 'dotdotdot', false );
186 }
187 );
188 return $dot;
189 }; // /bind_events
190
191 $dot.unbind_events = function()
192 {
193 $dot.unbind('.dot');
194 return $dot;
195 }; // /unbind_events
196
197 $dot.watch = function()
198 {
199 $dot.unwatch();
200 if ( opts.watch == 'window' )
201 {
202 var $window = $(window),
203 _wWidth = $window.width(),
204 _wHeight = $window.height();
205
206 $window.bind(
207 'resize.dot' + conf.dotId,
208 function()
209 {
210 if ( _wWidth != $window.width() || _wHeight != $window.height() || !opts.windowResizeFix )
211 {
212 _wWidth = $window.width();
213 _wHeight = $window.height();
214
215 if ( watchInt )
216 {
217 clearInterval( watchInt );
218 }
219 watchInt = setTimeout(
220 function()
221 {
222 $dot.trigger( 'update.dot' );
223 }, 100
224 );
225 }
226 }
227 );
228 }
229 else
230 {
231 watchOrg = getSizes( $dot );
232 watchInt = setInterval(
233 function()
234 {
235 if ( $dot.is( ':visible' ) )
236 {
237 var watchNew = getSizes( $dot );
238 if ( watchOrg.width != watchNew.width ||
239 watchOrg.height != watchNew.height )
240 {
241 $dot.trigger( 'update.dot' );
242 watchOrg = watchNew;
243 }
244 }
245 }, 500
246 );
247 }
248 return $dot;
249 };
250 $dot.unwatch = function()
251 {
252 $(window).unbind( 'resize.dot' + conf.dotId );
253 if ( watchInt )
254 {
255 clearInterval( watchInt );
256 }
257 return $dot;
258 };
259
260 var opts = $.extend( true, {}, $.fn.dotdotdot.defaults, o ),
261 conf = {},
262 watchOrg = {},
263 watchInt = null,
264 $inr = null;
265
266
267 if ( !( opts.lastCharacter.remove instanceof Array ) )
268 {
269 opts.lastCharacter.remove = $.fn.dotdotdot.defaultArrays.lastCharacter.remove;
270 }
271 if ( !( opts.lastCharacter.noEllipsis instanceof Array ) )
272 {
273 opts.lastCharacter.noEllipsis = $.fn.dotdotdot.defaultArrays.lastCharacter.noEllipsis;
274 }
275
276
277 conf.afterElement = getElement( opts.after, $dot );
278 conf.isTruncated = false;
279 conf.dotId = dotId++;
280
281
282 $dot.data( 'dotdotdot', true )
283 .bind_events()
284 .trigger( 'update.dot' );
285
286 if ( opts.watch )
287 {
288 $dot.watch();
289 }
290
291 return $dot;
292 };
293
294
295 // public
296 $.fn.dotdotdot.defaults = {
297 'ellipsis' : '... ',
298 'wrap' : 'word',
299 'fallbackToLetter' : true,
300 'lastCharacter' : {},
301 'tolerance' : 0,
302 'callback' : null,
303 'after' : null,
304 'height' : null,
305 'watch' : false,
306 'windowResizeFix' : true
307 };
308 $.fn.dotdotdot.defaultArrays = {
309 'lastCharacter' : {
310 'remove' : [ ' ', '\u3000', ',', ';', '.', '!', '?' ],
311 'noEllipsis' : []
312 }
313 };
314 $.fn.dotdotdot.debug = function( msg ) {};
315
316
317 // private
318 var dotId = 1;
319
320 function children( $elem, o, after )
321 {
322 var $elements = $elem.children(),
323 isTruncated = false;
324
325 $elem.empty();
326
327 for ( var a = 0, l = $elements.length; a < l; a++ )
328 {
329 var $e = $elements.eq( a );
330 $elem.append( $e );
331 if ( after )
332 {
333 $elem.append( after );
334 }
335 if ( test( $elem, o ) )
336 {
337 $e.remove();
338 isTruncated = true;
339 break;
340 }
341 else
342 {
343 if ( after )
344 {
345 after.detach();
346 }
347 }
348 }
349 return isTruncated;
350 }
351 function ellipsis( $elem, $d, $i, o, after )
352 {
353 var isTruncated = false;
354
355 // Don't put the ellipsis directly inside these elements
356 var notx = 'a, table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, blockquote, select, optgroup, option, textarea, script, style';
357
358 // Don't remove these elements even if they are after the ellipsis
359 var noty = 'script, .dotdotdot-keep';
360
361 $elem
362 .contents()
363 .detach()
364 .each(
365 function()
366 {
367
368 var e = this,
369 $e = $(e);
370
371 if ( typeof e == 'undefined' )
372 {
373 return true;
374 }
375 else if ( $e.is( noty ) )
376 {
377 $elem.append( $e );
378 }
379 else if ( isTruncated )
380 {
381 return true;
382 }
383 else
384 {
385 $elem.append( $e );
386 if ( after && !$e.is( o.after ) && !$e.find( o.after ).length )
387 {
388 $elem[ $elem.is( notx ) ? 'after' : 'append' ]( after );
389 }
390 if ( test( $i, o ) )
391 {
392 if ( e.nodeType == 3 ) // node is TEXT
393 {
394 isTruncated = ellipsisElement( $e, $d, $i, o, after );
395 }
396 else
397 {
398 isTruncated = ellipsis( $e, $d, $i, o, after );
399 }
400 }
401
402 if ( !isTruncated )
403 {
404 if ( after )
405 {
406 after.detach();
407 }
408 }
409 }
410 }
411 );
412 $d.addClass("is-truncated");
413 return isTruncated;
414 }
415 function ellipsisElement( $e, $d, $i, o, after )
416 {
417 var e = $e[ 0 ];
418
419 if ( !e )
420 {
421 return false;
422 }
423
424 var txt = getTextContent( e ),
425 space = ( txt.indexOf(' ') !== -1 ) ? ' ' : '\u3000',
426 separator = ( o.wrap == 'letter' ) ? '' : space,
427 textArr = txt.split( separator ),
428 position = -1,
429 midPos = -1,
430 startPos = 0,
431 endPos = textArr.length - 1;
432
433
434 // Only one word
435 if ( o.fallbackToLetter && startPos == 0 && endPos == 0 )
436 {
437 separator = '';
438 textArr = txt.split( separator );
439 endPos = textArr.length - 1;
440 }
441
442 while ( startPos <= endPos && !( startPos == 0 && endPos == 0 ) )
443 {
444 var m = Math.floor( ( startPos + endPos ) / 2 );
445 if ( m == midPos )
446 {
447 break;
448 }
449 midPos = m;
450
451 setTextContent( e, textArr.slice( 0, midPos + 1 ).join( separator ) + o.ellipsis );
452 $i.children()
453 .each(
454 function()
455 {
456 $(this).toggle().toggle();
457 }
458 );
459
460 if ( !test( $i, o ) )
461 {
462 position = midPos;
463 startPos = midPos;
464 }
465 else
466 {
467 endPos = midPos;
468
469 // Fallback to letter
470 if (o.fallbackToLetter && startPos == 0 && endPos == 0 )
471 {
472 separator = '';
473 textArr = textArr[ 0 ].split( separator );
474 position = -1;
475 midPos = -1;
476 startPos = 0;
477 endPos = textArr.length - 1;
478 }
479 }
480 }
481
482 if ( position != -1 && !( textArr.length == 1 && textArr[ 0 ].length == 0 ) )
483 {
484 txt = addEllipsis( textArr.slice( 0, position + 1 ).join( separator ), o );
485 setTextContent( e, txt );
486 }
487 else
488 {
489 var $w = $e.parent();
490 $e.detach();
491
492 var afterLength = ( after && after.closest($w).length ) ? after.length : 0;
493
494 if ( $w.contents().length > afterLength )
495 {
496 e = findLastTextNode( $w.contents().eq( -1 - afterLength ), $d );
497 }
498 else
499 {
500 e = findLastTextNode( $w, $d, true );
501 if ( !afterLength )
502 {
503 $w.detach();
504 }
505 }
506 if ( e )
507 {
508 txt = addEllipsis( getTextContent( e ), o );
509 setTextContent( e, txt );
510 if ( afterLength && after )
511 {
512 var $parent = after.parent();
513
514 $(e).parent().append( after );
515
516 if ( !$.trim( $parent.html() ) )
517 {
518 $parent.remove();
519 }
520 }
521 }
522 }
523
524 return true;
525 }
526 function test( $i, o )
527 {
528 return $i.innerHeight() > o.maxHeight;
529 }
530 function addEllipsis( txt, o )
531 {
532 while( $.inArray( txt.slice( -1 ), o.lastCharacter.remove ) > -1 )
533 {
534 txt = txt.slice( 0, -1 );
535 }
536 if ( $.inArray( txt.slice( -1 ), o.lastCharacter.noEllipsis ) < 0 )
537 {
538 txt += o.ellipsis;
539 }
540 return txt;
541 }
542 function getSizes( $d )
543 {
544 return {
545 'width' : $d.innerWidth(),
546 'height': $d.innerHeight()
547 };
548 }
549 function setTextContent( e, content )
550 {
551 if ( e.innerText )
552 {
553 e.innerText = content;
554 }
555 else if ( e.nodeValue )
556 {
557 e.nodeValue = content;
558 }
559 else if (e.textContent)
560 {
561 e.textContent = content;
562 }
563
564 }
565 function getTextContent( e )
566 {
567 if ( e.innerText )
568 {
569 return e.innerText;
570 }
571 else if ( e.nodeValue )
572 {
573 return e.nodeValue;
574 }
575 else if ( e.textContent )
576 {
577 return e.textContent;
578 }
579 else
580 {
581 return "";
582 }
583 }
584 function getPrevNode( n )
585 {
586 do
587 {
588 n = n.previousSibling;
589 }
590 while ( n && n.nodeType !== 1 && n.nodeType !== 3 );
591
592 return n;
593 }
594 function findLastTextNode( $el, $top, excludeCurrent )
595 {
596 var e = $el && $el[ 0 ], p;
597 if ( e )
598 {
599 if ( !excludeCurrent )
600 {
601 if ( e.nodeType === 3 )
602 {
603 return e;
604 }
605 if ( $.trim( $el.text() ) )
606 {
607 return findLastTextNode( $el.contents().last(), $top );
608 }
609 }
610 p = getPrevNode( e );
611 while ( !p )
612 {
613 $el = $el.parent();
614 if ( $el.is( $top ) || !$el.length )
615 {
616 return false;
617 }
618 p = getPrevNode( $el[0] );
619 }
620 if ( p )
621 {
622 return findLastTextNode( $(p), $top );
623 }
624 }
625 return false;
626 }
627 function getElement( e, $i )
628 {
629 if ( !e )
630 {
631 return false;
632 }
633 if ( typeof e === 'string' )
634 {
635 e = $(e, $i);
636 return ( e.length )
637 ? e
638 : false;
639 }
640 return !e.jquery
641 ? false
642 : e;
643 }
644 function getTrueInnerHeight( $el )
645 {
646 var h = $el.innerHeight(),
647 a = [ 'paddingTop', 'paddingBottom' ];
648
649 for ( var z = 0, l = a.length; z < l; z++ )
650 {
651 var m = parseInt( $el.css( a[ z ] ), 10 );
652 if ( isNaN( m ) )
653 {
654 m = 0;
655 }
656 h -= m;
657 }
658 return h;
659 }
660
661
662 // override jQuery.html
663 var _orgHtml = $.fn.html;
664 $.fn.html = function( str )
665 {
666 if ( str != undef && !$.isFunction( str ) && this.data( 'dotdotdot' ) )
667 {
668 return this.trigger( 'update', [ str ] );
669 }
670 return _orgHtml.apply( this, arguments );
671 };
672
673
674 // override jQuery.text
675 var _orgText = $.fn.text;
676 $.fn.text = function( str )
677 {
678 if ( str != undef && !$.isFunction( str ) && this.data( 'dotdotdot' ) )
679 {
680 str = $( '<div />' ).text( str ).html();
681 return this.trigger( 'update', [ str ] );
682 }
683 return _orgText.apply( this, arguments );
684 };
685
686
687})( jQuery );
688
689/*
690
691## Automatic parsing for CSS classes
692Contributed by [Ramil Valitov](https://github.com/rvalitov)
693
694### The idea
695You can add one or several CSS classes to HTML elements to automatically invoke "jQuery.dotdotdot functionality" and some extra features. It allows to use jQuery.dotdotdot only by adding appropriate CSS classes without JS programming.
696
697### Available classes and their description
698* dot-ellipsis - automatically invoke jQuery.dotdotdot to this element. This class must be included if you plan to use other classes below.
699* dot-resize-update - automatically update if window resize event occurs. It's equivalent to option `watch:'window'`.
700* dot-timer-update - automatically update if window resize event occurs. It's equivalent to option `watch:true`.
701* dot-load-update - automatically update after the window has beem completely rendered. Can be useful if your content is generated dynamically using using JS and, hence, jQuery.dotdotdot can't correctly detect the height of the element before it's rendered completely.
702* dot-height-XXX - available height of content area in pixels, where XXX is a number, e.g. can be `dot-height-35` if you want to set maximum height for 35 pixels. It's equivalent to option `height:'XXX'`.
703
704### Usage examples
705*Adding jQuery.dotdotdot to element*
706
707 <div class="dot-ellipsis">
708 <p>Lorem Ipsum is simply dummy text.</p>
709 </div>
710
711*Adding jQuery.dotdotdot to element with update on window resize*
712
713 <div class="dot-ellipsis dot-resize-update">
714 <p>Lorem Ipsum is simply dummy text.</p>
715 </div>
716
717*Adding jQuery.dotdotdot to element with predefined height of 50px*
718
719 <div class="dot-ellipsis dot-height-50">
720 <p>Lorem Ipsum is simply dummy text.</p>
721 </div>
722
723*/
724
725jQuery(document).ready(function($) {
726 //We only invoke jQuery.dotdotdot on elements that have dot-ellipsis class
727 $(".dot-ellipsis").each(function(){
728 //Checking if update on window resize required
729 var watch_window=$(this).hasClass("dot-resize-update");
730
731 //Checking if update on timer required
732 var watch_timer=$(this).hasClass("dot-timer-update");
733
734 //Checking if height set
735 var height=0;
736 var classList = $(this).attr('class').split(/\s+/);
737 $.each(classList, function(index, item) {
738 var matchResult = item.match(/^dot-height-(\d+)$/);
739 if(matchResult !== null)
740 height = Number(matchResult[1]);
741 });
742
743 //Invoking jQuery.dotdotdot
744 var x = new Object();
745 if (watch_timer)
746 x.watch=true;
747 if (watch_window)
748 x.watch='window';
749 if (height>0)
750 x.height=height;
751 $(this).dotdotdot(x);
752 });
753
754});
755
756//Updating elements (if any) on window.load event
757jQuery(window).on('load', function(){
758 jQuery(".dot-ellipsis.dot-load-update").trigger("update.dot");
759});