1/* 2 * jQuery dotdotdot 1.7.2 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 41 if ( $dot.data( 'dotdotdot' ) ) 42 { 43 $dot.trigger( 'destroy.dot' ); 44 } 45 46 $dot.data( 'dotdotdot-style', $dot.attr( 'style' ) || '' ); 47 $dot.css( 'word-wrap', 'break-word' ); 48 if ($dot.css( 'white-space' ) === 'nowrap') 49 { 50 $dot.css( 'white-space', 'normal' ); 51 } 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' || ('nodeType' in c && c.nodeType === 1) ) 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.contents() 82 .detach() 83 .end() 84 .append( orgContent.clone( true ) ) 85 .find( 'br' ) 86 .replaceWith( ' <br /> ' ) 87 .end() 88 .css({ 89 'height' : 'auto', 90 'width' : 'auto', 91 'border' : 'none', 92 'padding' : 0, 93 'margin' : 0 94 }); 95 96 var after = false, 97 trunc = false; 98 99 if ( conf.afterElement ) 100 { 101 after = conf.afterElement.clone( true ); 102 after.show(); 103 conf.afterElement.detach(); 104 } 105 106 if ( test( $inr, opts ) ) 107 { 108 if ( opts.wrap == 'children' ) 109 { 110 trunc = children( $inr, opts, after ); 111 } 112 else 113 { 114 trunc = ellipsis( $inr, $dot, $inr, opts, after ); 115 } 116 } 117 $inr.replaceWith( $inr.contents() ); 118 $inr = null; 119 120 if ( $.isFunction( opts.callback ) ) 121 { 122 opts.callback.call( $dot[ 0 ], trunc, orgContent ); 123 } 124 125 conf.isTruncated = trunc; 126 return trunc; 127 } 128 129 ).bind( 130 'isTruncated.dot', 131 function( e, fn ) 132 { 133 e.preventDefault(); 134 e.stopPropagation(); 135 136 if ( typeof fn == 'function' ) 137 { 138 fn.call( $dot[ 0 ], conf.isTruncated ); 139 } 140 return conf.isTruncated; 141 } 142 143 ).bind( 144 'originalContent.dot', 145 function( e, fn ) 146 { 147 e.preventDefault(); 148 e.stopPropagation(); 149 150 if ( typeof fn == 'function' ) 151 { 152 fn.call( $dot[ 0 ], orgContent ); 153 } 154 return orgContent; 155 } 156 157 ).bind( 158 'destroy.dot', 159 function( e ) 160 { 161 e.preventDefault(); 162 e.stopPropagation(); 163 164 $dot.unwatch() 165 .unbind_events() 166 .contents() 167 .detach() 168 .end() 169 .append( orgContent ) 170 .attr( 'style', $dot.data( 'dotdotdot-style' ) || '' ) 171 .data( 'dotdotdot', false ); 172 } 173 ); 174 return $dot; 175 }; // /bind_events 176 177 $dot.unbind_events = function() 178 { 179 $dot.unbind('.dot'); 180 return $dot; 181 }; // /unbind_events 182 183 $dot.watch = function() 184 { 185 $dot.unwatch(); 186 if ( opts.watch == 'window' ) 187 { 188 var $window = $(window), 189 _wWidth = $window.width(), 190 _wHeight = $window.height(); 191 192 $window.bind( 193 'resize.dot' + conf.dotId, 194 function() 195 { 196 if ( _wWidth != $window.width() || _wHeight != $window.height() || !opts.windowResizeFix ) 197 { 198 _wWidth = $window.width(); 199 _wHeight = $window.height(); 200 201 if ( watchInt ) 202 { 203 clearInterval( watchInt ); 204 } 205 watchInt = setTimeout( 206 function() 207 { 208 $dot.trigger( 'update.dot' ); 209 }, 100 210 ); 211 } 212 } 213 ); 214 } 215 else 216 { 217 watchOrg = getSizes( $dot ); 218 watchInt = setInterval( 219 function() 220 { 221 if ( $dot.is( ':visible' ) ) 222 { 223 var watchNew = getSizes( $dot ); 224 if ( watchOrg.width != watchNew.width || 225 watchOrg.height != watchNew.height ) 226 { 227 $dot.trigger( 'update.dot' );
228 watchOrg = watchNew; 229 } 230 } 231 }, 500 232 ); 233 } 234 return $dot; 235 }; 236 $dot.unwatch = function() 237 { 238 $(window).unbind( 'resize.dot' + conf.dotId ); 239 if ( watchInt ) 240 { 241 clearInterval( watchInt ); 242 } 243 return $dot; 244 }; 245 246 var orgContent = $dot.contents(), 247 opts = $.extend( true, {}, $.fn.dotdotdot.defaults, o ), 248 conf = {}, 249 watchOrg = {}, 250 watchInt = null, 251 $inr = null; 252 253 254 if ( !( opts.lastCharacter.remove instanceof Array ) ) 255 { 256 opts.lastCharacter.remove = $.fn.dotdotdot.defaultArrays.lastCharacter.remove; 257 } 258 if ( !( opts.lastCharacter.noEllipsis instanceof Array ) ) 259 { 260 opts.lastCharacter.noEllipsis = $.fn.dotdotdot.defaultArrays.lastCharacter.noEllipsis; 261 } 262 263 264 conf.afterElement = getElement( opts.after, $dot ); 265 conf.isTruncated = false; 266 conf.dotId = dotId++; 267 268 269 $dot.data( 'dotdotdot', true ) 270 .bind_events() 271 .trigger( 'update.dot' ); 272 273 if ( opts.watch ) 274 { 275 $dot.watch(); 276 } 277 278 return $dot; 279 }; 280 281 282 // public 283 $.fn.dotdotdot.defaults = { 284 'ellipsis' : '... ', 285 'wrap' : 'word', 286 'fallbackToLetter' : true, 287 'lastCharacter' : {}, 288 'tolerance' : 0, 289 'callback' : null, 290 'after' : null, 291 'height' : null, 292 'watch' : false, 293 'windowResizeFix' : true 294 }; 295 $.fn.dotdotdot.defaultArrays = { 296 'lastCharacter' : { 297 'remove' : [ ' ', '\u3000', ',', ';', '.', '!', '?' ], 298 'noEllipsis' : [] 299 } 300 }; 301 $.fn.dotdotdot.debug = function( msg ) {}; 302 303 304 // private 305 var dotId = 1; 306 307 function children( $elem, o, after ) 308 { 309 var $elements = $elem.children(), 310 isTruncated = false; 311 312 $elem.empty(); 313 314 for ( var a = 0, l = $elements.length; a < l; a++ ) 315 { 316 var $e = $elements.eq( a ); 317 $elem.append( $e ); 318 if ( after ) 319 {
320 $elem.append( after ); 321 } 322 if ( test( $elem, o ) ) 323 { 324 $e.remove(); 325 isTruncated = true; 326 break; 327 } 328 else 329 { 330 if ( after ) 331 { 332 after.detach(); 333 } 334 } 335 } 336 return isTruncated; 337 } 338 function ellipsis( $elem, $d, $i, o, after ) 339 { 340 var isTruncated = false; 341 342 // Don't put the ellipsis directly inside these elements 343 var notx = 'a table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, blockquote, select, optgroup, option, textarea, script, style'; 344 345 // Don't remove these elements even if they are after the ellipsis 346 var noty = 'script, .dotdotdot-keep'; 347 348 $elem 349 .contents() 350 .detach() 351 .each( 352 function() 353 { 354 355 var e = this, 356 $e = $(e); 357 358 if ( typeof e == 'undefined' || ( e.nodeType == 3 && $.trim( e.data ).length == 0 ) ) 359 { 360 return true; 361 } 362 else if ( $e.is( noty ) ) 363 { 364 $elem.append( $e ); 365 } 366 else if ( isTruncated ) 367 { 368 return true; 369 } 370 else 371 { 372 $elem.append( $e ); 373 if ( after && !$e.is( o.after ) && !$e.find( o.after ).length ) 374 { 375 $elem[ $elem.is( notx ) ? 'after' : 'append' ]( after ); 376 } 377 if ( test( $i, o ) ) 378 { 379 if ( e.nodeType == 3 ) // node is TEXT 380 { 381 isTruncated = ellipsisElement( $e, $d, $i, o, after ); 382 } 383 else 384 { 385 isTruncated = ellipsis( $e, $d, $i, o, after ); 386 } 387 388 if ( !isTruncated ) 389 { 390 $e.detach(); 391 isTruncated = true; 392 } 393 } 394 395 if ( !isTruncated ) 396 { 397 if ( after ) 398 { 399 after.detach(); 400 } 401 } 402 } 403 } 404 ); 405 406 return isTruncated; 407 } 408 function ellipsisElement( $e, $d, $i, o, after ) 409 { 410 var e = $e[ 0 ]; 411 412 if ( !e ) 413 { 414 return false; 415 } 416 417 var txt = getTextContent( e ), 418 space = ( txt.indexOf(' ') !== -1 ) ? ' ' : '\u3000', 419 separator = ( o.wrap == 'letter' ) ? '' : space, 420 textArr = txt.split( separator ), 421 position = -1, 422 midPos = -1, 423 startPos = 0, 424 endPos = textArr.length - 1; 425 426 427 // Only one word 428 if ( o.fallbackToLetter && startPos == 0 && endPos == 0 ) 429 { 430 separator = ''; 431 textArr = txt.split( separator ); 432 endPos = textArr.length - 1; 433 } 434 435 while ( startPos <= endPos && !( startPos == 0 && endPos == 0 ) ) 436 { 437 var m = Math.floor( ( startPos + endPos ) / 2 ); 438 if ( m == midPos ) 439 { 440 break; 441 } 442 midPos = m; 443 444 setTextContent( e, textArr.slice( 0, midPos + 1 ).join( separator ) + o.ellipsis ); 445 446 if ( !test( $i, o ) ) 447 { 448 position = midPos; 449 startPos = midPos; 450 } 451 else 452 { 453 endPos = midPos; 454 455 // Fallback to letter 456 if (o.fallbackToLetter && startPos == 0 && endPos == 0 ) 457 { 458 separator = ''; 459 textArr = textArr[ 0 ].split( separator ); 460 position = -1; 461 midPos = -1; 462 startPos = 0; 463 endPos = textArr.length - 1; 464 } 465 } 466 } 467 468 if ( position != -1 && !( textArr.length == 1 && textArr[ 0 ].length == 0 ) ) 469 { 470 txt = addEllipsis( textArr.slice( 0, position + 1 ).join( separator ), o ); 471 setTextContent( e, txt ); 472 } 473 else 474 { 475 var $w = $e.parent(); 476 $e.detach(); 477 478 var afterLength = ( after && after.closest($w).length ) ? after.length : 0; 479 480 if ( $w.contents().length > afterLength ) 481 { 482 e = findLastTextNode( $w.contents().eq( -1 - afterLength ), $d ); 483 } 484 else 485 { 486 e = findLastTextNode( $w, $d, true ); 487 if ( !afterLength ) 488 { 489 $w.detach(); 490 } 491 } 492 if ( e ) 493 { 494 txt = addEllipsis( getTextContent( e ), o ); 495 setTextContent( e, txt ); 496 if ( afterLength && after ) 497 { 498 $(e).parent().append( after ); 499 } 500 } 501 } 502 503 return true; 504 } 505 function test( $i, o ) 506 { 507 return $i.innerHeight() > o.maxHeight; 508 } 509 function addEllipsis( txt, o ) 510 { 511 while( $.inArray( txt.slice( -1 ), o.lastCharacter.remove ) > -1 ) 512 { 513 txt = txt.slice( 0, -1 ); 514 } 515 if ( $.inArray( txt.slice( -1 ), o.lastCharacter.noEllipsis ) < 0 ) 516 { 517 txt += o.ellipsis; 518 } 519 return txt; 520 } 521 function getSizes( $d ) 522 { 523 return { 524 'width' : $d.innerWidth(), 525 'height': $d.innerHeight() 526 }; 527 } 528 function setTextContent( e, content ) 529 { 530 if ( e.innerText ) 531 {
532 e.innerText = content; 533 } 534 else if ( e.nodeValue ) 535 { 536 e.nodeValue = content; 537 } 538 else if (e.textContent) 539 { 540 e.textContent = content; 541 } 542 543 } 544 function getTextContent( e ) 545 { 546 if ( e.innerText ) 547 { 548 return e.innerText; 549 } 550 else if ( e.nodeValue ) 551 { 552 return e.nodeValue; 553 } 554 else if ( e.textContent ) 555 { 556 return e.textContent; 557 } 558 else 559 { 560 return ""; 561 } 562 } 563 function getPrevNode( n ) 564 { 565 do 566 { 567 n = n.previousSibling; 568 } 569 while ( n && n.nodeType !== 1 && n.nodeType !== 3 ); 570 571 return n; 572 } 573 function findLastTextNode( $el, $top, excludeCurrent ) 574 { 575 var e = $el && $el[ 0 ], p; 576 if ( e ) 577 { 578 if ( !excludeCurrent ) 579 { 580 if ( e.nodeType === 3 ) 581 { 582 return e; 583 } 584 if ( $.trim( $el.text() ) ) 585 { 586 return findLastTextNode( $el.contents().last(), $top ); 587 } 588 } 589 p = getPrevNode( e ); 590 while ( !p ) 591 { 592 $el = $el.parent(); 593 if ( $el.is( $top ) || !$el.length ) 594 { 595 return false; 596 } 597 p = getPrevNode( $el[0] ); 598 } 599 if ( p ) 600 { 601 return findLastTextNode( $(p), $top ); 602 } 603 } 604 return false; 605 } 606 function getElement( e, $i ) 607 { 608 if ( !e ) 609 { 610 return false; 611 } 612 if ( typeof e === 'string' ) 613 { 614 e = $(e, $i); 615 return ( e.length ) 616 ? e 617 : false; 618 } 619 return !e.jquery 620 ? false 621 : e; 622 } 623 function getTrueInnerHeight( $el ) 624 { 625 var h = $el.innerHeight(), 626 a = [ 'paddingTop', 'paddingBottom' ]; 627 628 for ( var z = 0, l = a.length; z < l; z++ ) 629 { 630 var m = parseInt( $el.css( a[ z ] ), 10 ); 631 if ( isNaN( m ) ) 632 { 633 m = 0; 634 } 635 h -= m; 636 } 637 return h; 638 } 639 640 641 // override jQuery.html 642 var _orgHtml = $.fn.html; 643 $.fn.html = function( str ) 644 { 645 if ( str != undef && !$.isFunction( str ) && this.data( 'dotdotdot' ) ) 646 { 647 return this.trigger( 'update', [ str ] ); 648 } 649 return _orgHtml.apply( this, arguments ); 650 }; 651 652 653 // override jQuery.text 654 var _orgText = $.fn.text; 655 $.fn.text = function( str ) 656 { 657 if ( str != undef && !$.isFunction( str ) && this.data( 'dotdotdot' ) ) 658 { 659 str = $( '<div />' ).text( str ).html(); 660 return this.trigger( 'update', [ str ] ); 661 } 662 return _orgText.apply( this, arguments ); 663 }; 664 665 666})( 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.