• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mac-s-g / react-json-view / #1382

01 Dec 2022 10:27AM UTC coverage: 80.707% (-2.5%) from 83.246%
#1382

push

asburyj
updated package.json peer dependencies for react and react-dom

281 of 366 branches covered (76.78%)

Branch coverage included in aggregate %.

518 of 624 relevant lines covered (83.01%)

35.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.22
/src/js/components/DataTypes/Object.js
1
import React from 'react';
2
import { polyfill } from 'react-lifecycles-compat';
3
import { countKeys, toType } from './../../helpers/util';
4

5
//data type components
6
import { JsonObject } from './DataTypes';
7

8
import VariableEditor from './../VariableEditor';
9
import VariableMeta from './../VariableMeta';
10
import ArrayGroup from './../ArrayGroup';
11
import ObjectName from './../ObjectName';
12

13
//attribute store
14
import AttributeStore from './../../stores/ObjectAttributes';
15

16
//icons
17
import { CollapsedIcon, ExpandedIcon } from './../ToggleIcons';
18

19
//theme
20
import Theme from './../../themes/getStyle';
21

22
//increment 1 with each nested object & array
23
const DEPTH_INCREMENT = 1;
1✔
24
//single indent is 5px
25
const SINGLE_INDENT = 5;
1✔
26

27
class RjvObject extends React.PureComponent {
28
    constructor(props) {
29
        super(props);
43✔
30
        const state = RjvObject.getState(props);
43✔
31
        this.state = {
21✔
32
            ...state,
33
            prevProps: {}
34
        };
35
    }
36

37
    static getState = props => {
1✔
38
        const size = Object.keys(props.src).length;
72✔
39
        const keys = [];
72✔
40
        props.highlight.forEach((h) => {
72✔
41
            keys.push(h.key);
×
42
        });
43
        const amountClickable = countKeys(keys, props.src);
50✔
44
        const expanded =
45
            (props.collapsed === false ||
50!
46
                (props.collapsed !== true && props.collapsed > props.depth)) &&
47
            (!props.shouldCollapse ||
48
                props.shouldCollapse({
49
                    name: props.name,
50
                    src: props.src,
51
                    type: toType(props.src),
52
                    namespace: props.namespace
53
                }) === false) &&
54
            //initialize closed if object has no items
55
            size !== 0;
56
        const state = {
50✔
57
            expanded: AttributeStore.get(
58
                props.rjvId,
59
                props.namespace,
60
                'expanded',
61
                expanded
62
            ),
63
            object_type: props.type === 'array' ? 'array' : 'object',
50✔
64
            parent_type: props.type === 'array' ? 'array' : 'object',
50✔
65
            size,
66
            amountClickable,
67
            hovered: false
68
        };
69
        return state;
50✔
70
    };
71

72
    static getDerivedStateFromProps(nextProps, prevState) {
73
        const { prevProps } = prevState;
29✔
74
        if (
29!
75
            nextProps.src !== prevProps.src ||
50!
76
            nextProps.collapsed !== prevProps.collapsed ||
77
            nextProps.name !== prevProps.name ||
78
            nextProps.namespace !== prevProps.namespace ||
79
            nextProps.rjvId !== prevProps.rjvId
80
        ) {
81
            const newState = RjvObject.getState(nextProps);
29✔
82
            return {
29✔
83
                ...newState,
84
                prevProps: nextProps
85
            };
86
        }
87
        return null;
×
88
    }
89

90
    toggleCollapsed = () => {
43✔
91
        this.setState(
×
92
            {
93
                expanded: !this.state.expanded
94
            },
95
            () => {
96
                AttributeStore.set(
×
97
                    this.props.rjvId,
98
                    this.props.namespace,
99
                    'expanded',
100
                    this.state.expanded
101
                );
102
            }
103
        );
104
    };
105

106
    getObjectContent = (depth, src, props) => {
43✔
107
        return (
27✔
108
            <div class="pushed-content object-container">
109
                <div
110
                    class="object-content"
111
                    {...Theme(this.props.theme, 'pushed-content')}
112
                >
113
                    {this.renderObjectContents(src, props)}
114
                </div>
115
            </div>
116
        );
117
    };
118

119
    getEllipsis = () => {
43✔
120
        const { size } = this.state;
2✔
121

122
        if (size === 0) {
2!
123
            //don't render an ellipsis when an object has no items
124
            return null;
2✔
125
        } else {
126
            return (
×
127
                <div
128
                    {...Theme(this.props.theme, 'ellipsis')}
129
                    class="node-ellipsis"
130
                    onClick={this.toggleCollapsed}
131
                >
132
                    ...
133
                </div>
134
            );
135
        }
136
    };
137

138
    getObjectMetaData = src => {
43✔
139
        const { rjvId, theme } = this.props;
29✔
140
        const { size, amountClickable, hovered } = this.state;
29✔
141
        return (
29✔
142
            <VariableMeta rowHovered={hovered} size={size} amountClickable={amountClickable} {...this.props} />
143
        );
144
    };
145

146
    getBraceStart(object_type, expanded) {
147
        const { src, theme, iconStyle, parent_type } = this.props;
29✔
148

149
        if (parent_type === 'array_group') {
29!
150
            return (
×
151
                <span>
152
                    <span {...Theme(theme, 'brace')}>
153
                        {object_type === 'array' ? '[' : '{'}
×
154
                    </span>
155
                    {expanded ? this.getObjectMetaData(src) : null}
×
156
                </span>
157
            );
158
        }
159

160
        const IconComponent = expanded ? ExpandedIcon : CollapsedIcon;
29✔
161

162
        return (
29✔
163
            <span>
164
                <span
165
                    onClick={e => {
166
                        this.toggleCollapsed();
×
167
                    }}
168
                    {...Theme(theme, 'brace-row')}
169
                >
170
                    <div
171
                        class="icon-container"
172
                        {...Theme(theme, 'icon-container')}
173
                    >
174
                        <IconComponent {...{ theme, iconStyle }} />
175
                    </div>
176
                    <ObjectName {...this.props} />
177
                    <span {...Theme(theme, 'brace')}>
178
                        {object_type === 'array' ? '[' : '{'}
29✔
179
                    </span>
180
                </span>
181
                {expanded ? this.getObjectMetaData(src) : null}
29✔
182
            </span>
183
        );
184
    }
185

186
    render() {
187
        // `indentWidth` and `collapsed` props will
188
        // perpetuate to children via `...rest`
189
        const {
190
            depth,
191
            src,
192
            namespace,
193
            name,
194
            type,
195
            parent_type,
196
            theme,
197
            jsvRoot,
198
            iconStyle,
199
            ...rest
200
        } = this.props;
29✔
201

202
        const { object_type, expanded } = this.state;
29✔
203

204
        let styles = {};
29✔
205
        if (!jsvRoot && parent_type !== 'array_group') {
29✔
206
            styles.paddingLeft = this.props.indentWidth * SINGLE_INDENT;
20✔
207
        } else if (parent_type === 'array_group') {
9!
208
            styles.borderLeft = 0;
×
209
            styles.display = 'inline';
×
210
        }
211

212
        return (
29✔
213
            <div
214
                class="object-key-val"
215
                onMouseEnter={() =>
216
                    this.setState({ ...this.state, hovered: true })
×
217
                }
218
                onMouseLeave={() =>
219
                    this.setState({ ...this.state, hovered: false })
×
220
                }
221
                {...Theme(theme, jsvRoot ? 'jsv-root' : 'objectKeyVal', styles)}
29✔
222
            >
223
                {this.getBraceStart(object_type, expanded)}
224
                {expanded
29✔
225
                    ? this.getObjectContent(depth, src, {
226
                          theme,
227
                          iconStyle,
228
                          ...rest
229
                      })
230
                    : this.getEllipsis()}
231
                <span class="brace-row">
232
                    <span
233
                        style={{
234
                            ...Theme(theme, 'brace').style,
235
                            paddingLeft: expanded ? '3px' : '0px'
29✔
236
                        }}
237
                    >
238
                        {object_type === 'array' ? ']' : '}'}
29✔
239
                    </span>
240
                    {expanded ? null : this.getObjectMetaData(src)}
29✔
241
                </span>
242
            </div>
243
        );
244
    }
245

246
    renderObjectContents = (variables, props) => {
43✔
247
        const {
248
            depth,
249
            parent_type,
250
            index_offset,
251
            groupArraysAfterLength,
252
            namespace
253
        } = this.props;
27✔
254
        const { object_type } = this.state;
27✔
255
        let elements = [],
27✔
256
            variable;
257
        let keys = Object.keys(variables || {});
27!
258
        if (this.props.sortKeys && object_type !== 'array') {
27!
259
            keys = keys.sort();
×
260
        }
261

262
        keys.forEach(name => {
27✔
263
            variable = new JsonVariable(name, variables[name]);
79✔
264

265
            if (parent_type === 'array_group' && index_offset) {
79!
266
                variable.name = parseInt(variable.name) + index_offset;
×
267
            }
268
            if (!variables.hasOwnProperty(name)) {
79!
269
                return;
×
270
            } else if (variable.type === 'object') {
79✔
271
                elements.push(
10✔
272
                    <JsonObject
273
                        key={variable.name}
274
                        depth={depth + DEPTH_INCREMENT}
275
                        name={variable.name}
276
                        src={variable.value}
277
                        namespace={namespace.concat(variable.name)}
278
                        parent_type={object_type}
279
                        {...props}
280
                    />
281
                );
282
            } else if (variable.type === 'array') {
69✔
283
                let ObjectComponent = JsonObject;
10✔
284

285
                if (
10!
286
                    groupArraysAfterLength &&
20✔
287
                    variable.value.length > groupArraysAfterLength
288
                ) {
289
                    ObjectComponent = ArrayGroup;
×
290
                }
291

292
                elements.push(
10✔
293
                    <ObjectComponent
294
                        key={variable.name}
295
                        depth={depth + DEPTH_INCREMENT}
296
                        name={variable.name}
297
                        src={variable.value}
298
                        namespace={namespace.concat(variable.name)}
299
                        type="array"
300
                        parent_type={object_type}
301
                        {...props}
302
                    />
303
                );
304
            } else {
305
                elements.push(
59✔
306
                    <VariableEditor
307
                        key={variable.name + '_' + namespace}
308
                        variable={variable}
309
                        singleIndent={SINGLE_INDENT}
310
                        namespace={namespace}
311
                        type={this.props.type}
312
                        {...props}
313
                    />
314
                );
315
            }
316
        });
317

318
        return elements;
27✔
319
    };
320
}
321

322
//just store name, value and type with a variable
323
class JsonVariable {
324
    constructor(name, value) {
325
        this.name = name;
79✔
326
        this.value = value;
79✔
327
        this.type = toType(value);
79✔
328
    }
329
}
330

331
polyfill(RjvObject);
1✔
332

333
//export component
334
export default RjvObject;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc