@@ -5,6 +5,32 @@ import PropTypes from 'prop-types';
55import measureText from 'measure-text' ;
66import units from 'units-css' ;
77
8+ const getStartOffset = ( start , text ) => {
9+ if ( start === '' || start === null ) {
10+ return 0 ;
11+ }
12+
13+ if ( ! isNaN ( parseInt ( start , 10 ) ) ) {
14+ return Math . round ( toFinite ( start ) ) ;
15+ }
16+
17+ const result = new RegExp ( start ) . exec ( text ) ;
18+ return result ? result . index + result [ 0 ] . length : 0 ;
19+ } ;
20+
21+ const getEndOffset = ( end , text ) => {
22+ if ( end === '' || end === null ) {
23+ return 0 ;
24+ }
25+
26+ if ( ! isNaN ( parseInt ( end , 10 ) ) ) {
27+ return Math . round ( toFinite ( end ) ) ;
28+ }
29+
30+ const result = new RegExp ( end ) . exec ( text ) ;
31+ return result ? result [ 0 ] . length : 0 ;
32+ } ;
33+
834// A React component for truncating text in the middle of the string.
935//
1036// This component automatically calculates the required width and height of the text
@@ -21,24 +47,13 @@ class MiddleTruncate extends PureComponent {
2147 static propTypes = {
2248 className : PropTypes . string ,
2349 ellipsis : PropTypes . string ,
24- end : PropTypes . oneOfType ( [
25- PropTypes . number ,
26- PropTypes . instanceOf ( RegExp ) ,
27- PropTypes . string
28- ] ) ,
50+ end : PropTypes . oneOfType ( [ PropTypes . number , PropTypes . instanceOf ( RegExp ) , PropTypes . string ] ) ,
2951 onResizeDebounceMs : PropTypes . number ,
30- smartCopy : PropTypes . oneOfType ( [
31- PropTypes . oneOf ( [ 'partial' , 'all' ] ) ,
32- PropTypes . bool
33- ] ) ,
34- start : PropTypes . oneOfType ( [
35- PropTypes . number ,
36- PropTypes . instanceOf ( RegExp ) ,
37- PropTypes . string
38- ] ) ,
52+ smartCopy : PropTypes . oneOfType ( [ PropTypes . oneOf ( [ 'partial' , 'all' ] ) , PropTypes . bool ] ) ,
53+ start : PropTypes . oneOfType ( [ PropTypes . number , PropTypes . instanceOf ( RegExp ) , PropTypes . string ] ) ,
3954 style : PropTypes . object ,
4055 text : PropTypes . string
41- } ;
56+ }
4257
4358 static defaultProps = {
4459 className : '' ,
@@ -49,26 +64,12 @@ class MiddleTruncate extends PureComponent {
4964 start : 0 ,
5065 style : { } ,
5166 text : ''
52- } ;
53-
54- constructor ( props ) {
55- super ( props ) ;
56-
57- this . getStartOffset = this . getStartOffset . bind ( this ) ;
58- this . getEndOffset = this . getEndOffset . bind ( this ) ;
59- this . onCopy = this . onCopy . bind ( this ) ;
60- this . calculateMeasurements = this . calculateMeasurements . bind ( this ) ;
61- this . truncateText = this . truncateText . bind ( this ) ;
62-
63- // Debounce the parsing of the text so that the component has had time to render its DOM for measurement calculations
64- this . parseTextForTruncation = debounce ( this . parseTextForTruncation . bind ( this ) , 0 ) ;
65- this . onResize = debounce ( this . onResize . bind ( this ) , this . props . onResizeDebounceMs ) ;
6667 }
6768
6869 state = {
6970 truncatedText : this . props . text ,
70- start : this . getStartOffset ( this . props . start , this . props . text ) ,
71- end : this . getEndOffset ( this . props . end , this . props . text )
71+ start : getStartOffset ( this . props . start , this . props . text ) ,
72+ end : getEndOffset ( this . props . end , this . props . text )
7273 }
7374
7475 componentDidMount ( ) {
@@ -82,19 +83,19 @@ class MiddleTruncate extends PureComponent {
8283 }
8384
8485 if ( nextProps . start !== this . props . start ) {
85- this . setState ( { start : this . getStartOffset ( nextProps . start , nextProps . text ) } ) ;
86+ this . setState ( { start : getStartOffset ( nextProps . start , nextProps . text ) } ) ;
8687 }
8788
8889 if ( nextProps . end !== this . props . end ) {
89- this . setState ( { end : this . getEndOffset ( nextProps . end , nextProps . text ) } ) ;
90+ this . setState ( { end : getEndOffset ( nextProps . end , nextProps . text ) } ) ;
9091 }
9192 }
9293
9394 componentWillUnmount ( ) {
9495 window . removeEventListener ( 'resize' , this . onResize ) ;
9596 }
9697
97- onCopy ( event ) {
98+ onCopy = event => {
9899 const { smartCopy } = this . props ;
99100
100101 // If smart copy is not enabled, simply return and use the default behaviour of the copy event
@@ -106,45 +107,19 @@ class MiddleTruncate extends PureComponent {
106107
107108 // If smartCopy is set to partial or if smartCopy is set to all and the entire string was selected
108109 // copy the original full text to the user's clipboard
109- if ( smartCopy === 'partial' || ( smartCopy === 'all' && selectedText === this . state . truncatedText ) ) {
110+ if ( smartCopy === 'partial' || ( smartCopy === 'all' && selectedText === this . state . truncatedText ) ) {
110111 event . preventDefault ( ) ;
111112 const clipboardData = event . clipboardData || window . clipboardData || event . originalEvent . clipboardData ;
112113
113114 clipboardData . setData ( 'text/plain' , this . props . text ) ;
114115 }
115116 }
116117
117- onResize ( ) {
118+ onResize = debounce ( ( ) => {
118119 this . parseTextForTruncation ( this . props . text ) ;
119- }
120-
121- getStartOffset ( start , text ) {
122- if ( start === '' || start === null ) {
123- return 0 ;
124- }
125-
126- if ( ! isNaN ( parseInt ( start , 10 ) ) ) {
127- return Math . round ( toFinite ( start ) ) ;
128- }
129-
130- const result = new RegExp ( start ) . exec ( text ) ;
131- return result ? result . index + result [ 0 ] . length : 0 ;
132- }
120+ } , this . props . onResizeDebounceMs )
133121
134- getEndOffset ( end , text ) {
135- if ( end === '' || end === null ) {
136- return 0 ;
137- }
138-
139- if ( ! isNaN ( parseInt ( end , 10 ) ) ) {
140- return Math . round ( toFinite ( end ) ) ;
141- }
142-
143- const result = new RegExp ( end ) . exec ( text ) ;
144- return result ? result [ 0 ] . length : 0 ;
145- }
146-
147- getTextMeasurement = ( ref ) => {
122+ getTextMeasurement = ref => {
148123 const node = findDOMNode ( ref ) ;
149124 const text = node . textContent ;
150125
@@ -185,7 +160,7 @@ class MiddleTruncate extends PureComponent {
185160 } ;
186161 }
187162
188- truncateText ( measurements ) {
163+ truncateText = measurements => {
189164 const { text, ellipsis } = this . props ;
190165 const { start, end } = this . state ;
191166
@@ -194,7 +169,7 @@ class MiddleTruncate extends PureComponent {
194169 }
195170
196171 const delta = Math . ceil ( measurements . text . width . value - measurements . component . width . value ) ;
197- const totalLettersToRemove = Math . ceil ( ( ( delta / measurements . ellipsis . width . value ) ) ) ;
172+ const totalLettersToRemove = Math . ceil ( delta / measurements . ellipsis . width . value ) ;
198173 const middleIndex = Math . round ( text . length / 2 ) ;
199174
200175 const preserveLeftSide = text . slice ( 0 , start ) ;
@@ -205,15 +180,17 @@ class MiddleTruncate extends PureComponent {
205180 return `${ preserveLeftSide } ${ leftSide } ${ ellipsis } ${ rightSide } ${ preserveRightSide } ` ;
206181 }
207182
208- parseTextForTruncation ( text ) {
183+ // Debounce the parsing of the text so that the component has had time to render its DOM for measurement calculations
184+ parseTextForTruncation = debounce ( text => {
209185 const measurements = this . calculateMeasurements ( ) ;
210186
211- const truncatedText = ( Math . round ( measurements . text . width . value ) > Math . round ( measurements . component . width . value ) )
212- ? this . truncateText ( measurements )
213- : text ;
187+ const truncatedText =
188+ Math . round ( measurements . text . width . value ) > Math . round ( measurements . component . width . value )
189+ ? this . truncateText ( measurements )
190+ : text ;
214191
215192 this . setState ( ( ) => ( { truncatedText } ) ) ;
216- }
193+ } , 0 )
217194
218195 render ( ) {
219196 // eslint-disable-next-line no-unused-vars
0 commit comments