Merge "'lang' attrib in #mw-content-text should be set to variant code."
[lhc/web/wiklou.git] / resources / jquery / jquery.autoEllipsis.js
1 /**
2 * Plugin that automatically truncates the plain text contents of an element and adds an ellipsis
3 */
4 ( function ( $ ) {
5
6 var
7 // Cache ellipsed substrings for every string-width-position combination
8 cache = { },
9
10 // Use a separate cache when match highlighting is enabled
11 matchTextCache = { };
12
13 $.fn.autoEllipsis = function ( options ) {
14 options = $.extend( {
15 position: 'center',
16 tooltip: false,
17 restoreText: false,
18 hasSpan: false,
19 matchText: null
20 }, options );
21 $(this).each( function () {
22 var $container, $trimmableText,
23 text, trimmableText, w, pw,
24 l, r, i, side, m,
25 $el = $(this);
26 if ( options.restoreText ) {
27 if ( !$el.data( 'autoEllipsis.originalText' ) ) {
28 $el.data( 'autoEllipsis.originalText', $el.text() );
29 } else {
30 $el.text( $el.data( 'autoEllipsis.originalText' ) );
31 }
32 }
33
34 // container element - used for measuring against
35 $container = $el;
36
37 // trimmable text element - only the text within this element will be trimmed
38 if ( options.hasSpan ) {
39 $trimmableText = $el.children( options.selector );
40 } else {
41 $trimmableText = $( '<span>' )
42 .css( 'whiteSpace', 'nowrap' )
43 .text( $el.text() );
44 $el
45 .empty()
46 .append( $trimmableText );
47 }
48
49 text = $container.text();
50 trimmableText = $trimmableText.text();
51 w = $container.width();
52 pw = 0;
53
54 // Try cache
55 if ( options.matchText ) {
56 if ( !( text in matchTextCache ) ) {
57 matchTextCache[text] = {};
58 }
59 if ( !( options.matchText in matchTextCache[text] ) ) {
60 matchTextCache[text][options.matchText] = {};
61 }
62 if ( !( w in matchTextCache[text][options.matchText] ) ) {
63 matchTextCache[text][options.matchText][w] = {};
64 }
65 if ( options.position in matchTextCache[text][options.matchText][w] ) {
66 $container.html( matchTextCache[text][options.matchText][w][options.position] );
67 if ( options.tooltip ) {
68 $container.attr( 'title', text );
69 }
70 return;
71 }
72 } else {
73 if ( !( text in cache ) ) {
74 cache[text] = {};
75 }
76 if ( !( w in cache[text] ) ) {
77 cache[text][w] = {};
78 }
79 if ( options.position in cache[text][w] ) {
80 $container.html( cache[text][w][options.position] );
81 if ( options.tooltip ) {
82 $container.attr( 'title', text );
83 }
84 return;
85 }
86 }
87
88 if ( $trimmableText.width() + pw > w ) {
89 switch ( options.position ) {
90 case 'right':
91 // Use binary search-like technique for efficiency
92 l = 0;
93 r = trimmableText.length;
94 do {
95 m = Math.ceil( ( l + r ) / 2 );
96 $trimmableText.text( trimmableText.substr( 0, m ) + '...' );
97 if ( $trimmableText.width() + pw > w ) {
98 // Text is too long
99 r = m - 1;
100 } else {
101 l = m;
102 }
103 } while ( l < r );
104 $trimmableText.text( trimmableText.substr( 0, l ) + '...' );
105 break;
106 case 'center':
107 // TODO: Use binary search like for 'right'
108 i = [Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 )];
109 // Begin with making the end shorter
110 side = 1;
111 while ( $trimmableText.outerWidth() + pw > w && i[0] > 0 ) {
112 $trimmableText.text( trimmableText.substr( 0, i[0] ) + '...' + trimmableText.substr( i[1] ) );
113 // Alternate between trimming the end and begining
114 if ( side === 0 ) {
115 // Make the begining shorter
116 i[0]--;
117 side = 1;
118 } else {
119 // Make the end shorter
120 i[1]++;
121 side = 0;
122 }
123 }
124 break;
125 case 'left':
126 // TODO: Use binary search like for 'right'
127 r = 0;
128 while ( $trimmableText.outerWidth() + pw > w && r < trimmableText.length ) {
129 $trimmableText.text( '...' + trimmableText.substr( r ) );
130 r++;
131 }
132 break;
133 }
134 }
135 if ( options.tooltip ) {
136 $container.attr( 'title', text );
137 }
138 if ( options.matchText ) {
139 $container.highlightText( options.matchText );
140 matchTextCache[text][options.matchText][w][options.position] = $container.html();
141 } else {
142 cache[text][w][options.position] = $container.html();
143 }
144
145 } );
146 };
147
148 }( jQuery ) );