Implement extension registration from an extension.json file
[mediawiki.git] / resources / src / jquery / jquery.autoEllipsis.js
blob9a196b5dbc51c65a0a04cdaa4e7634be7702f318
1 /**
2  * @class jQuery.plugin.autoEllipsis
3  */
4 ( function ( $ ) {
6 var
7         // Cache ellipsed substrings for every string-width-position combination
8         cache = {},
10         // Use a separate cache when match highlighting is enabled
11         matchTextCache = {};
13 /**
14  * Automatically truncate the plain text contents of an element and add an ellipsis
15  *
16  * @param {Object} options
17  * @param {'center'|'left'|'right'} [options.position='center'] Where to remove text.
18  * @param {boolean} [options.tooltip=false] Whether to show a tooltip with the remainder
19  * of the text.
20  * @param {boolean} [options.restoreText=false] Whether to save the text for restoring
21  * later.
22  * @param {boolean} [options.hasSpan=false] Whether the element is already a container,
23  * or if the library should create a new container for it.
24  * @param {string|null} [options.matchText=null] Text to highlight, e.g. search terms.
25  * @return {jQuery}
26  * @chainable
27  */
28 $.fn.autoEllipsis = function ( options ) {
29         options = $.extend( {
30                 position: 'center',
31                 tooltip: false,
32                 restoreText: false,
33                 hasSpan: false,
34                 matchText: null
35         }, options );
37         return this.each( function () {
38                 var $trimmableText,
39                         text, trimmableText, w, pw,
40                         l, r, i, side, m,
41                         // container element - used for measuring against
42                         $container = $( this );
44                 if ( options.restoreText ) {
45                         if ( !$container.data( 'autoEllipsis.originalText' ) ) {
46                                 $container.data( 'autoEllipsis.originalText', $container.text() );
47                         } else {
48                                 $container.text( $container.data( 'autoEllipsis.originalText' ) );
49                         }
50                 }
52                 // trimmable text element - only the text within this element will be trimmed
53                 if ( options.hasSpan ) {
54                         $trimmableText = $container.children( options.selector );
55                 } else {
56                         $trimmableText = $( '<span>' )
57                                 .css( 'whiteSpace', 'nowrap' )
58                                 .text( $container.text() );
59                         $container
60                                 .empty()
61                                 .append( $trimmableText );
62                 }
64                 text = $container.text();
65                 trimmableText = $trimmableText.text();
66                 w = $container.width();
67                 pw = 0;
69                 // Try cache
70                 if ( options.matchText ) {
71                         if ( !( text in matchTextCache ) ) {
72                                 matchTextCache[text] = {};
73                         }
74                         if ( !( options.matchText in matchTextCache[text] ) ) {
75                                 matchTextCache[text][options.matchText] = {};
76                         }
77                         if ( !( w in matchTextCache[text][options.matchText] ) ) {
78                                 matchTextCache[text][options.matchText][w] = {};
79                         }
80                         if ( options.position in matchTextCache[text][options.matchText][w] ) {
81                                 $container.html( matchTextCache[text][options.matchText][w][options.position] );
82                                 if ( options.tooltip ) {
83                                         $container.attr( 'title', text );
84                                 }
85                                 return;
86                         }
87                 } else {
88                         if ( !( text in cache ) ) {
89                                 cache[text] = {};
90                         }
91                         if ( !( w in cache[text] ) ) {
92                                 cache[text][w] = {};
93                         }
94                         if ( options.position in cache[text][w] ) {
95                                 $container.html( cache[text][w][options.position] );
96                                 if ( options.tooltip ) {
97                                         $container.attr( 'title', text );
98                                 }
99                                 return;
100                         }
101                 }
103                 if ( $trimmableText.width() + pw > w ) {
104                         switch ( options.position ) {
105                                 case 'right':
106                                         // Use binary search-like technique for efficiency
107                                         l = 0;
108                                         r = trimmableText.length;
109                                         do {
110                                                 m = Math.ceil( ( l + r ) / 2 );
111                                                 $trimmableText.text( trimmableText.slice( 0, m ) + '...' );
112                                                 if ( $trimmableText.width() + pw > w ) {
113                                                         // Text is too long
114                                                         r = m - 1;
115                                                 } else {
116                                                         l = m;
117                                                 }
118                                         } while ( l < r );
119                                         $trimmableText.text( trimmableText.slice( 0, l ) + '...' );
120                                         break;
121                                 case 'center':
122                                         // TODO: Use binary search like for 'right'
123                                         i = [Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 )];
124                                         // Begin with making the end shorter
125                                         side = 1;
126                                         while ( $trimmableText.outerWidth() + pw > w && i[0] > 0 ) {
127                                                 $trimmableText.text( trimmableText.slice( 0, i[0] ) + '...' + trimmableText.slice( i[1] ) );
128                                                 // Alternate between trimming the end and begining
129                                                 if ( side === 0 ) {
130                                                         // Make the begining shorter
131                                                         i[0]--;
132                                                         side = 1;
133                                                 } else {
134                                                         // Make the end shorter
135                                                         i[1]++;
136                                                         side = 0;
137                                                 }
138                                         }
139                                         break;
140                                 case 'left':
141                                         // TODO: Use binary search like for 'right'
142                                         r = 0;
143                                         while ( $trimmableText.outerWidth() + pw > w && r < trimmableText.length ) {
144                                                 $trimmableText.text( '...' + trimmableText.slice( r ) );
145                                                 r++;
146                                         }
147                                         break;
148                         }
149                 }
150                 if ( options.tooltip ) {
151                         $container.attr( 'title', text );
152                 }
153                 if ( options.matchText ) {
154                         $container.highlightText( options.matchText );
155                         matchTextCache[text][options.matchText][w][options.position] = $container.html();
156                 } else {
157                         cache[text][w][options.position] = $container.html();
158                 }
160         } );
164  * @class jQuery
165  * @mixins jQuery.plugin.autoEllipsis
166  */
168 }( jQuery ) );