@@ -9,16 +9,20 @@ import { dateStringUTC } from 'lib/DateUtils';
9
9
import getFileName from 'lib/getFileName' ;
10
10
import Parse from 'parse' ;
11
11
import Pill from 'components/Pill/Pill.react' ;
12
- import React , { useEffect , useRef }
13
- from 'react' ;
12
+ import React , { Component } from 'react' ;
14
13
import styles from 'components/BrowserCell/BrowserCell.scss' ;
15
14
import { unselectable } from 'stylesheets/base.scss' ;
16
15
17
- let BrowserCell = ( { type, value, hidden, width, current, onSelect, onEditChange, setRelation, onPointerClick } ) => {
18
- const cellRef = current ? useRef ( ) : null ;
19
- if ( current ) {
20
- useEffect ( ( ) => {
21
- const node = cellRef . current ;
16
+ export default class BrowserCell extends Component {
17
+ constructor ( ) {
18
+ super ( ) ;
19
+
20
+ this . cellRef = React . createRef ( ) ;
21
+ }
22
+
23
+ componentDidUpdate ( ) {
24
+ if ( this . props . current ) {
25
+ const node = this . cellRef . current ;
22
26
const { left, right, bottom, top } = node . getBoundingClientRect ( ) ;
23
27
24
28
// Takes into consideration Sidebar width when over 980px wide.
@@ -28,118 +32,137 @@ let BrowserCell = ({ type, value, hidden, width, current, onSelect, onEditChange
28
32
const topBoundary = 126 ;
29
33
30
34
if ( left < leftBoundary || right > window . innerWidth ) {
31
- node . scrollIntoView ( { behavior : 'smooth' , block : 'nearest' , inline : 'start' } ) ;
35
+ node . scrollIntoView ( { block : 'nearest' , inline : 'start' } ) ;
32
36
} else if ( top < topBoundary || bottom > window . innerHeight ) {
33
- node . scrollIntoView ( { behavior : 'smooth' , block : 'nearest' , inline : 'nearest' } ) ;
37
+ node . scrollIntoView ( { block : 'nearest' , inline : 'nearest' } ) ;
34
38
}
35
- } ) ;
39
+ }
36
40
}
37
41
38
- let content = value ;
39
- let classes = [ styles . cell , unselectable ] ;
40
- if ( hidden ) {
41
- content = '(hidden)' ;
42
- classes . push ( styles . empty ) ;
43
- } else if ( value === undefined ) {
44
- if ( type === 'ACL' ) {
45
- content = 'Public Read + Write' ;
46
- } else {
47
- content = '(undefined)' ;
48
- classes . push ( styles . empty ) ;
49
- }
50
- } else if ( value === null ) {
51
- content = '(null)' ;
52
- classes . push ( styles . empty ) ;
53
- } else if ( value === '' ) {
54
- content = < span > </ span > ;
55
- classes . push ( styles . empty ) ;
56
- } else if ( type === 'Pointer' ) {
57
- if ( value && value . __type ) {
58
- const object = new Parse . Object ( value . className ) ;
59
- object . id = value . objectId ;
60
- value = object ;
42
+ shouldComponentUpdate ( nextProps ) {
43
+ const shallowVerifyProps = [ ...new Set ( Object . keys ( this . props ) . concat ( Object . keys ( nextProps ) ) ) ]
44
+ . filter ( propName => propName !== 'value' ) ;
45
+ if ( shallowVerifyProps . some ( propName => this . props [ propName ] !== nextProps [ propName ] ) ) {
46
+ return true ;
61
47
}
62
- content = (
63
- < a href = 'javascript:;' onClick = { onPointerClick . bind ( undefined , value ) } >
64
- < Pill value = { value . id } />
65
- </ a >
66
- ) ;
67
- } else if ( type === 'Date' ) {
68
- if ( typeof value === 'object' && value . __type ) {
69
- value = new Date ( value . iso ) ;
70
- } else if ( typeof value === 'string' ) {
71
- value = new Date ( value ) ;
48
+ const { value } = this . props ;
49
+ const { value : nextValue } = nextProps ;
50
+ if ( typeof value !== typeof nextValue ) {
51
+ return true ;
72
52
}
73
- content = dateStringUTC ( value ) ;
74
- } else if ( type === 'Boolean' ) {
75
- content = value ? 'True' : 'False' ;
76
- } else if ( type === 'Object' || type === 'Bytes' || type === 'Array' ) {
77
- content = JSON . stringify ( value ) ;
78
- } else if ( type === 'File' ) {
79
- if ( value . url ( ) ) {
80
- content = < Pill value = { getFileName ( value ) } /> ;
81
- } else {
82
- content = < Pill value = { 'Uploading\u2026' } /> ;
53
+ const isRefDifferent = value !== nextValue ;
54
+ if ( isRefDifferent && typeof value === 'object' ) {
55
+ return JSON . stringify ( value ) !== JSON . stringify ( nextValue ) ;
83
56
}
84
- } else if ( type === 'ACL' ) {
85
- let pieces = [ ] ;
86
- let json = value . toJSON ( ) ;
87
- if ( Object . prototype . hasOwnProperty . call ( json , '*' ) ) {
88
- if ( json [ '*' ] . read && json [ '*' ] . write ) {
89
- pieces . push ( 'Public Read + Write' ) ;
90
- } else if ( json [ '*' ] . read ) {
91
- pieces . push ( 'Public Read' ) ;
92
- } else if ( json [ '*' ] . write ) {
93
- pieces . push ( 'Public Write' ) ;
57
+ return isRefDifferent ;
58
+ }
59
+
60
+ render ( ) {
61
+ let { type, value, hidden, width, current, onSelect, onEditChange, setRelation, onPointerClick, row, col } = this . props ;
62
+ let content = value ;
63
+ let classes = [ styles . cell , unselectable ] ;
64
+ if ( hidden ) {
65
+ content = '(hidden)' ;
66
+ classes . push ( styles . empty ) ;
67
+ } else if ( value === undefined ) {
68
+ if ( type === 'ACL' ) {
69
+ content = 'Public Read + Write' ;
70
+ } else {
71
+ content = '(undefined)' ;
72
+ classes . push ( styles . empty ) ;
94
73
}
95
- }
96
- for ( let role in json ) {
97
- if ( role !== '*' ) {
98
- pieces . push ( role ) ;
74
+ } else if ( value === null ) {
75
+ content = '(null)' ;
76
+ classes . push ( styles . empty ) ;
77
+ } else if ( value === '' ) {
78
+ content = < span > </ span > ;
79
+ classes . push ( styles . empty ) ;
80
+ } else if ( type === 'Pointer' ) {
81
+ if ( value && value . __type ) {
82
+ const object = new Parse . Object ( value . className ) ;
83
+ object . id = value . objectId ;
84
+ value = object ;
85
+ }
86
+ content = (
87
+ < a href = 'javascript:;' onClick = { onPointerClick . bind ( undefined , value ) } >
88
+ < Pill value = { value . id } />
89
+ </ a >
90
+ ) ;
91
+ } else if ( type === 'Date' ) {
92
+ if ( typeof value === 'object' && value . __type ) {
93
+ value = new Date ( value . iso ) ;
94
+ } else if ( typeof value === 'string' ) {
95
+ value = new Date ( value ) ;
99
96
}
97
+ content = dateStringUTC ( value ) ;
98
+ } else if ( type === 'Boolean' ) {
99
+ content = value ? 'True' : 'False' ;
100
+ } else if ( type === 'Object' || type === 'Bytes' || type === 'Array' ) {
101
+ content = JSON . stringify ( value ) ;
102
+ } else if ( type === 'File' ) {
103
+ if ( value . url ( ) ) {
104
+ content = < Pill value = { getFileName ( value ) } /> ;
105
+ } else {
106
+ content = < Pill value = { 'Uploading\u2026' } /> ;
107
+ }
108
+ } else if ( type === 'ACL' ) {
109
+ let pieces = [ ] ;
110
+ let json = value . toJSON ( ) ;
111
+ if ( Object . prototype . hasOwnProperty . call ( json , '*' ) ) {
112
+ if ( json [ '*' ] . read && json [ '*' ] . write ) {
113
+ pieces . push ( 'Public Read + Write' ) ;
114
+ } else if ( json [ '*' ] . read ) {
115
+ pieces . push ( 'Public Read' ) ;
116
+ } else if ( json [ '*' ] . write ) {
117
+ pieces . push ( 'Public Write' ) ;
118
+ }
119
+ }
120
+ for ( let role in json ) {
121
+ if ( role !== '*' ) {
122
+ pieces . push ( role ) ;
123
+ }
124
+ }
125
+ if ( pieces . length === 0 ) {
126
+ pieces . push ( 'Master Key Only' ) ;
127
+ }
128
+ content = pieces . join ( ', ' ) ;
129
+ } else if ( type === 'GeoPoint' ) {
130
+ content = `(${ value . latitude } , ${ value . longitude } )` ;
131
+ } else if ( type === 'Polygon' ) {
132
+ content = value . coordinates . map ( coord => `(${ coord } )` )
133
+ } else if ( type === 'Relation' ) {
134
+ content = (
135
+ < div style = { { textAlign : 'center' , cursor : 'pointer' } } >
136
+ < Pill onClick = { ( ) => setRelation ( value ) } value = 'View relation' />
137
+ </ div >
138
+ ) ;
100
139
}
101
- if ( pieces . length === 0 ) {
102
- pieces . push ( 'Master Key Only' ) ;
140
+
141
+ if ( current ) {
142
+ classes . push ( styles . current ) ;
103
143
}
104
- content = pieces . join ( ', ' ) ;
105
- } else if ( type === 'GeoPoint' ) {
106
- content = `(${ value . latitude } , ${ value . longitude } )` ;
107
- } else if ( type === 'Polygon' ) {
108
- content = value . coordinates . map ( coord => `(${ coord } )` )
109
- } else if ( type === 'Relation' ) {
110
- content = (
111
- < div style = { { textAlign : 'center' , cursor : 'pointer' } } >
112
- < Pill onClick = { ( ) => setRelation ( value ) } value = 'View relation' />
113
- </ div >
144
+ return (
145
+ < span
146
+ ref = { this . cellRef }
147
+ className = { classes . join ( ' ' ) }
148
+ style = { { width } }
149
+ onClick = { ( ) => onSelect ( { row, col } ) }
150
+ onDoubleClick = { ( ) => {
151
+ if ( type !== 'Relation' ) {
152
+ onEditChange ( true )
153
+ }
154
+ } }
155
+ onTouchEnd = { e => {
156
+ if ( current && type !== 'Relation' ) {
157
+ // The touch event may trigger an unwanted change in the column value
158
+ if ( [ 'ACL' , 'Boolean' , 'File' ] . includes ( type ) ) {
159
+ e . preventDefault ( ) ;
160
+ }
161
+ onEditChange ( true ) ;
162
+ }
163
+ } } >
164
+ { content }
165
+ </ span >
114
166
) ;
115
167
}
116
-
117
- if ( current ) {
118
- classes . push ( styles . current ) ;
119
- }
120
- return (
121
- < span
122
- ref = { cellRef }
123
- className = { classes . join ( ' ' ) }
124
- style = { { width } }
125
- onClick = { onSelect }
126
- onDoubleClick = { ( ) => {
127
- if ( type !== 'Relation' ) {
128
- onEditChange ( true )
129
- }
130
- } }
131
- onTouchEnd = { e => {
132
- if ( current && type !== 'Relation' ) {
133
- // The touch event may trigger an unwanted change in the column value
134
- if ( [ 'ACL' , 'Boolean' , 'File' ] . includes ( type ) ) {
135
- e . preventDefault ( ) ;
136
- }
137
- onEditChange ( true ) ;
138
- }
139
- } } >
140
- { content }
141
- </ span >
142
- ) ;
143
- } ;
144
-
145
- export default BrowserCell ;
168
+ }
0 commit comments