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