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});
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.