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