jquery.dotdotdot-1.5.9.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*
  2. * jQuery dotdotdot 1.5.9
  3. *
  4. * Copyright (c) 2013 Fred Heusschen
  5. * www.frebsite.nl
  6. *
  7. * Plugin website:
  8. * dotdotdot.frebsite.nl
  9. *
  10. * Dual licensed under the MIT and GPL licenses.
  11. * http://en.wikipedia.org/wiki/MIT_License
  12. * http://en.wikipedia.org/wiki/GNU_General_Public_License
  13. */
  14. (function( $ )
  15. {
  16. if ( $.fn.dotdotdot )
  17. {
  18. return;
  19. }
  20. $.fn.dotdotdot = function( o )
  21. {
  22. if ( this.length == 0 )
  23. {
  24. if ( !o || o.debug !== false )
  25. {
  26. debug( true, 'No element found for "' + this.selector + '".' );
  27. }
  28. return this;
  29. }
  30. if ( this.length > 1 )
  31. {
  32. return this.each(
  33. function()
  34. {
  35. $(this).dotdotdot( o );
  36. }
  37. );
  38. }
  39. var $dot = this;
  40. if ( $dot.data( 'dotdotdot' ) )
  41. {
  42. $dot.trigger( 'destroy.dot' );
  43. }
  44. $dot.data( 'dotdotdot-style', $dot.attr( 'style' ) );
  45. $dot.css( 'word-wrap', 'break-word' );
  46. $dot.bind_events = function()
  47. {
  48. $dot.bind(
  49. 'update.dot',
  50. function( e, c )
  51. {
  52. e.preventDefault();
  53. e.stopPropagation();
  54. opts.maxHeight = ( typeof opts.height == 'number' )
  55. ? opts.height
  56. : getTrueInnerHeight( $dot );
  57. opts.maxHeight += opts.tolerance;
  58. if ( typeof c != 'undefined' )
  59. {
  60. if ( typeof c == 'string' || c instanceof HTMLElement )
  61. {
  62. c = $('<div />').append( c ).contents();
  63. }
  64. if ( c instanceof $ )
  65. {
  66. orgContent = c;
  67. }
  68. }
  69. $inr = $dot.wrapInner( '<div class="dotdotdot" />' ).children();
  70. $inr.empty()
  71. .append( orgContent.clone( true ) )
  72. .css({
  73. 'height' : 'auto',
  74. 'width' : 'auto',
  75. 'border' : 'none',
  76. 'padding' : 0,
  77. 'margin' : 0
  78. });
  79. var after = false,
  80. trunc = false;
  81. if ( conf.afterElement )
  82. {
  83. after = conf.afterElement.clone( true );
  84. conf.afterElement.remove();
  85. }
  86. if ( test( $inr, opts ) )
  87. {
  88. if ( opts.wrap == 'children' )
  89. {
  90. trunc = children( $inr, opts, after );
  91. }
  92. else
  93. {
  94. trunc = ellipsis( $inr, $dot, $inr, opts, after );
  95. }
  96. }
  97. $inr.replaceWith( $inr.contents() );
  98. $inr = null;
  99. if ( $.isFunction( opts.callback ) )
  100. {
  101. opts.callback.call( $dot[ 0 ], trunc, orgContent );
  102. }
  103. conf.isTruncated = trunc;
  104. return trunc;
  105. }
  106. ).bind(
  107. 'isTruncated.dot',
  108. function( e, fn )
  109. {
  110. e.preventDefault();
  111. e.stopPropagation();
  112. if ( typeof fn == 'function' )
  113. {
  114. fn.call( $dot[ 0 ], conf.isTruncated );
  115. }
  116. return conf.isTruncated;
  117. }
  118. ).bind(
  119. 'originalContent.dot',
  120. function( e, fn )
  121. {
  122. e.preventDefault();
  123. e.stopPropagation();
  124. if ( typeof fn == 'function' )
  125. {
  126. fn.call( $dot[ 0 ], orgContent );
  127. }
  128. return orgContent;
  129. }
  130. ).bind(
  131. 'destroy.dot',
  132. function( e )
  133. {
  134. e.preventDefault();
  135. e.stopPropagation();
  136. $dot.unwatch()
  137. .unbind_events()
  138. .empty()
  139. .append( orgContent )
  140. .attr( 'style', $dot.data( 'dotdotdot-style' ) )
  141. .data( 'dotdotdot', false );
  142. }
  143. );
  144. return $dot;
  145. }; // /bind_events
  146. $dot.unbind_events = function()
  147. {
  148. $dot.unbind('.dot');
  149. return $dot;
  150. }; // /unbind_events
  151. $dot.watch = function()
  152. {
  153. $dot.unwatch();
  154. if ( opts.watch == 'window' )
  155. {
  156. var $window = $(window),
  157. _wWidth = $window.width(),
  158. _wHeight = $window.height();
  159. $window.bind(
  160. 'resize.dot' + conf.dotId,
  161. function()
  162. {
  163. if ( _wWidth != $window.width() || _wHeight != $window.height() || !opts.windowResizeFix )
  164. {
  165. _wWidth = $window.width();
  166. _wHeight = $window.height();
  167. if ( watchInt )
  168. {
  169. clearInterval( watchInt );
  170. }
  171. watchInt = setTimeout(
  172. function()
  173. {
  174. $dot.trigger( 'update.dot' );
  175. }, 10
  176. );
  177. }
  178. }
  179. );
  180. }
  181. else
  182. {
  183. watchOrg = getSizes( $dot );
  184. watchInt = setInterval(
  185. function()
  186. {
  187. var watchNew = getSizes( $dot );
  188. if ( watchOrg.width != watchNew.width ||
  189. watchOrg.height != watchNew.height )
  190. {
  191. $dot.trigger( 'update.dot' );
  192. watchOrg = getSizes( $dot );
  193. }
  194. }, 100
  195. );
  196. }
  197. return $dot;
  198. };
  199. $dot.unwatch = function()
  200. {
  201. $(window).unbind( 'resize.dot' + conf.dotId );
  202. if ( watchInt )
  203. {
  204. clearInterval( watchInt );
  205. }
  206. return $dot;
  207. };
  208. var orgContent = $dot.contents(),
  209. opts = $.extend( true, {}, $.fn.dotdotdot.defaults, o ),
  210. conf = {},
  211. watchOrg = {},
  212. watchInt = null,
  213. $inr = null;
  214. conf.afterElement = getElement( opts.after, $dot );
  215. conf.isTruncated = false;
  216. conf.dotId = dotId++;
  217. $dot.data( 'dotdotdot', true )
  218. .bind_events()
  219. .trigger( 'update.dot' );
  220. if ( opts.watch )
  221. {
  222. $dot.watch();
  223. }
  224. return $dot;
  225. };
  226. // public
  227. $.fn.dotdotdot.defaults = {
  228. 'ellipsis' : '... ',
  229. 'wrap' : 'word',
  230. 'lastCharacter': {
  231. 'remove' : [ ' ', ',', ';', '.', '!', '?' ],
  232. 'noEllipsis' : []
  233. },
  234. 'tolerance' : 0,
  235. 'callback' : null,
  236. 'after' : null,
  237. 'height' : null,
  238. 'watch' : false,
  239. 'windowResizeFix': true,
  240. 'debug' : false
  241. };
  242. // private
  243. var dotId = 1;
  244. function children( $elem, o, after )
  245. {
  246. var $elements = $elem.children(),
  247. isTruncated = false;
  248. $elem.empty();
  249. for ( var a = 0, l = $elements.length; a < l; a++ )
  250. {
  251. var $e = $elements.eq( a );
  252. $elem.append( $e );
  253. if ( after )
  254. {
  255. $elem.append( after );
  256. }
  257. if ( test( $elem, o ) )
  258. {
  259. $e.remove();
  260. isTruncated = true;
  261. break;
  262. }
  263. else
  264. {
  265. if ( after )
  266. {
  267. after.remove();
  268. }
  269. }
  270. }
  271. return isTruncated;
  272. }
  273. function ellipsis( $elem, $d, $i, o, after )
  274. {
  275. var $elements = $elem.contents(),
  276. isTruncated = false;
  277. $elem.empty();
  278. var notx = 'table, thead, tbody, tfoot, tr, col, colgroup, object, embed, param, ol, ul, dl, select, optgroup, option, textarea, script, style';
  279. for ( var a = 0, l = $elements.length; a < l; a++ )
  280. {
  281. if ( isTruncated )
  282. {
  283. break;
  284. }
  285. var e = $elements[ a ],
  286. $e = $(e);
  287. if ( typeof e == 'undefined' )
  288. {
  289. continue;
  290. }
  291. $elem.append( $e );
  292. if ( after )
  293. {
  294. $elem[ ( $elem.is( notx ) ) ? 'after' : 'append' ]( after );
  295. }
  296. if ( e.nodeType == 3 )
  297. {
  298. if ( test( $i, o ) )
  299. {
  300. isTruncated = ellipsisElement( $e, $d, $i, o, after );
  301. }
  302. }
  303. else
  304. {
  305. isTruncated = ellipsis( $e, $d, $i, o, after );
  306. }
  307. if ( !isTruncated )
  308. {
  309. if ( after )
  310. {
  311. after.remove();
  312. }
  313. }
  314. }
  315. return isTruncated;
  316. }
  317. function ellipsisElement( $e, $d, $i, o, after )
  318. {
  319. var isTruncated = false,
  320. e = $e[ 0 ];
  321. if ( typeof e == 'undefined' )
  322. {
  323. return false;
  324. }
  325. var seporator = ( o.wrap == 'letter' ) ? '' : ' ',
  326. textArr = getTextContent( e ).split( seporator ),
  327. position = -1,
  328. midPos = -1,
  329. startPos = 0,
  330. endPos = textArr.length - 1;
  331. while ( startPos <= endPos )
  332. {
  333. var m = Math.floor( ( startPos + endPos ) / 2 );
  334. if ( m == midPos )
  335. {
  336. break;
  337. }
  338. midPos = m;
  339. setTextContent( e, textArr.slice( 0, midPos + 1 ).join( seporator ) + o.ellipsis );
  340. if ( !test( $i, o ) )
  341. {
  342. position = midPos;
  343. startPos = midPos;
  344. }
  345. else
  346. {
  347. endPos = midPos;
  348. }
  349. }
  350. if ( position != -1 && !( textArr.length == 1 && textArr[ 0 ].length == 0 ) )
  351. {
  352. var txt = addEllipsis( textArr.slice( 0, position + 1 ).join( seporator ), o );
  353. isTruncated = true;
  354. setTextContent( e, txt );
  355. }
  356. else
  357. {
  358. var $w = $e.parent();
  359. $e.remove();
  360. var afterLength = ( after ) ? after.length : 0 ;
  361. if ( $w.contents().size() > afterLength )
  362. {
  363. var $n = $w.contents().eq( -1 - afterLength );
  364. isTruncated = ellipsisElement( $n, $d, $i, o, after );
  365. }
  366. else
  367. {
  368. var $p = $w.prev()
  369. var e = $p.contents().eq( -1 )[ 0 ];
  370. if ( typeof e != 'undefined' )
  371. {
  372. var txt = addEllipsis( getTextContent( e ), o );
  373. setTextContent( e, txt );
  374. if ( after )
  375. {
  376. $p.append( after );
  377. }
  378. $w.remove();
  379. isTruncated = true;
  380. }
  381. }
  382. }
  383. return isTruncated;
  384. }
  385. function test( $i, o )
  386. {
  387. return $i.innerHeight() > o.maxHeight;
  388. }
  389. function addEllipsis( txt, o )
  390. {
  391. while( $.inArray( txt.slice( -1 ), o.lastCharacter.remove ) > -1 )
  392. {
  393. txt = txt.slice( 0, -1 );
  394. }
  395. if ( $.inArray( txt.slice( -1 ), o.lastCharacter.noEllipsis ) < 0 )
  396. {
  397. txt += o.ellipsis;
  398. }
  399. return txt;
  400. }
  401. function getSizes( $d )
  402. {
  403. return {
  404. 'width' : $d.innerWidth(),
  405. 'height': $d.innerHeight()
  406. };
  407. }
  408. function setTextContent( e, content )
  409. {
  410. if ( e.innerText )
  411. {
  412. e.innerText = content;
  413. }
  414. else if ( e.nodeValue )
  415. {
  416. e.nodeValue = content;
  417. }
  418. else if (e.textContent)
  419. {
  420. e.textContent = content;
  421. }
  422. }
  423. function getTextContent( e )
  424. {
  425. if ( e.innerText )
  426. {
  427. return e.innerText;
  428. }
  429. else if ( e.nodeValue )
  430. {
  431. return e.nodeValue;
  432. }
  433. else if ( e.textContent )
  434. {
  435. return e.textContent;
  436. }
  437. else
  438. {
  439. return "";
  440. }
  441. }
  442. function getElement( e, $i )
  443. {
  444. if ( typeof e == 'undefined' )
  445. {
  446. return false;
  447. }
  448. if ( !e )
  449. {
  450. return false;
  451. }
  452. if ( typeof e == 'string' )
  453. {
  454. e = $(e, $i);
  455. return ( e.length )
  456. ? e
  457. : false;
  458. }
  459. if ( typeof e == 'object' )
  460. {
  461. return ( typeof e.jquery == 'undefined' )
  462. ? false
  463. : e;
  464. }
  465. return false;
  466. }
  467. function getTrueInnerHeight( $el )
  468. {
  469. var h = $el.innerHeight(),
  470. a = [ 'paddingTop', 'paddingBottom' ];
  471. for ( var z = 0, l = a.length; z < l; z++ ) {
  472. var m = parseInt( $el.css( a[ z ] ), 10 );
  473. if ( isNaN( m ) )
  474. {
  475. m = 0;
  476. }
  477. h -= m;
  478. }
  479. return h;
  480. }
  481. function debug( d, m )
  482. {
  483. if ( !d )
  484. {
  485. return false;
  486. }
  487. if ( typeof m == 'string' )
  488. {
  489. m = 'dotdotdot: ' + m;
  490. }
  491. else
  492. {
  493. m = [ 'dotdotdot:', m ];
  494. }
  495. if ( typeof window.console != 'undefined' )
  496. {
  497. if ( typeof window.console.log != 'undefined' )
  498. {
  499. window.console.log( m );
  500. }
  501. }
  502. return false;
  503. }
  504. // override jQuery.html
  505. var _orgHtml = $.fn.html;
  506. $.fn.html = function( str ) {
  507. if ( typeof str != 'undefined' )
  508. {
  509. if ( this.data( 'dotdotdot' ) )
  510. {
  511. if ( typeof str != 'function' )
  512. {
  513. return this.trigger( 'update', [ str ] );
  514. }
  515. }
  516. return _orgHtml.call( this, str );
  517. }
  518. return _orgHtml.call( this );
  519. };
  520. // override jQuery.text
  521. var _orgText = $.fn.text;
  522. $.fn.text = function( str ) {
  523. if ( typeof str != 'undefined' )
  524. {
  525. if ( this.data( 'dotdotdot' ) )
  526. {
  527. var temp = $( '<div />' );
  528. temp.text( str );
  529. str = temp.html();
  530. temp.remove();
  531. return this.trigger( 'update', [ str ] );
  532. }
  533. return _orgText.call( this, str );
  534. }
  535. return _orgText.call( this );
  536. };
  537. })( jQuery );