2 * @class jQuery.plugin.autoEllipsis
7 // Cache ellipsed substrings for every string-width-position combination
10 // Use a separate cache when match highlighting is enabled
13 // Due to <https://github.com/jscs-dev/jscs-jsdoc/issues/136>
16 * Automatically truncate the plain text contents of an element and add an ellipsis
18 * @param {Object} options
19 * @param {'left'|'center'|'right'} [options.position='center'] Where to remove text.
20 * @param {boolean} [options.tooltip=false] Whether to show a tooltip with the remainder
22 * @param {boolean} [options.restoreText=false] Whether to save the text for restoring
24 * @param {boolean} [options.hasSpan=false] Whether the element is already a container,
25 * or if the library should create a new container for it.
26 * @param {string|null} [options.matchText=null] Text to highlight, e.g. search terms.
30 $.fn.autoEllipsis = function ( options ) {
39 return this.each( function () {
41 text, trimmableText, w, pw,
43 // container element - used for measuring against
44 $container = $( this );
46 if ( options.restoreText ) {
47 if ( !$container.data( 'autoEllipsis.originalText' ) ) {
48 $container.data( 'autoEllipsis.originalText', $container.text() );
50 $container.text( $container.data( 'autoEllipsis.originalText' ) );
54 // trimmable text element - only the text within this element will be trimmed
55 if ( options.hasSpan ) {
56 $trimmableText = $container.children( options.selector );
58 $trimmableText = $( '<span>' )
59 .css( 'whiteSpace', 'nowrap' )
60 .text( $container.text() );
63 .append( $trimmableText );
66 text = $container.text();
67 trimmableText = $trimmableText.text();
68 w = $container.width();
72 if ( options.matchText ) {
73 if ( !( text in matchTextCache ) ) {
74 matchTextCache[ text ] = {};
76 if ( !( options.matchText in matchTextCache[ text ] ) ) {
77 matchTextCache[ text ][ options.matchText ] = {};
79 if ( !( w in matchTextCache[ text ][ options.matchText ] ) ) {
80 matchTextCache[ text ][ options.matchText ][ w ] = {};
82 if ( options.position in matchTextCache[ text ][ options.matchText ][ w ] ) {
83 $container.html( matchTextCache[ text ][ options.matchText ][ w ][ options.position ] );
84 if ( options.tooltip ) {
85 $container.attr( 'title', text );
90 if ( !( text in cache ) ) {
93 if ( !( w in cache[ text ] ) ) {
94 cache[ text ][ w ] = {};
96 if ( options.position in cache[ text ][ w ] ) {
97 $container.html( cache[ text ][ w ][ options.position ] );
98 if ( options.tooltip ) {
99 $container.attr( 'title', text );
105 if ( $trimmableText.width() + pw > w ) {
106 switch ( options.position ) {
108 // Use binary search-like technique for efficiency
110 r = trimmableText.length;
112 m = Math.ceil( ( l + r ) / 2 );
113 $trimmableText.text( trimmableText.slice( 0, m ) + '...' );
114 if ( $trimmableText.width() + pw > w ) {
121 $trimmableText.text( trimmableText.slice( 0, l ) + '...' );
124 // TODO: Use binary search like for 'right'
125 i = [ Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 ) ];
126 // Begin with making the end shorter
128 while ( $trimmableText.outerWidth() + pw > w && i[ 0 ] > 0 ) {
129 $trimmableText.text( trimmableText.slice( 0, i[ 0 ] ) + '...' + trimmableText.slice( i[ 1 ] ) );
130 // Alternate between trimming the end and begining
132 // Make the begining shorter
136 // Make the end shorter
143 // TODO: Use binary search like for 'right'
145 while ( $trimmableText.outerWidth() + pw > w && r < trimmableText.length ) {
146 $trimmableText.text( '...' + trimmableText.slice( r ) );
152 if ( options.tooltip ) {
153 $container.attr( 'title', text );
155 if ( options.matchText ) {
156 $container.highlightText( options.matchText );
157 matchTextCache[ text ][ options.matchText ][ w ][ options.position ] = $container.html();
159 cache[ text ][ w ][ options.position ] = $container.html();
168 * @mixins jQuery.plugin.autoEllipsis