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

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

13 Mar 2022 11:07AM UTC coverage: 82.86% (-0.4%) from 83.21%
#2071

push

Slavik
Bump to version 1.21.4

284 of 351 branches covered (80.91%)

Branch coverage included in aggregate %.

504 of 600 relevant lines covered (84.0%)

44.87 hits per line

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

86.11
/src/js/components/DataTypes/Object.js
1
import React from 'react';
2
import { polyfill } from 'react-lifecycles-compat';
3
import { 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);
46✔
30
        const state = RjvObject.getState(props);
46✔
31
        this.state = {
46✔
32
            ...state,
33
            prevProps: {}
34
        };
35
    }
36

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

66
    static getDerivedStateFromProps(nextProps, prevState) {
67
        const { prevProps } = prevState;
54✔
68
        if (
54!
69
            nextProps.src !== prevProps.src ||
75!
70
            nextProps.collapsed !== prevProps.collapsed ||
71
            nextProps.name !== prevProps.name ||
72
            nextProps.namespace !== prevProps.namespace ||
73
            nextProps.rjvId !== prevProps.rjvId
74
        ) {
75
            const newState = RjvObject.getState(nextProps);
54✔
76
            return {
54✔
77
                ...newState,
78
                prevProps: nextProps
79
            };
80
        }
81
        return null;
×
82
    }
83

84
    toggleCollapsed = () => {
46✔
85
        const { onToggleCollapse, name, namespace, rjvId } = this.props;
×
86

87
        this.setState(
×
88
            {
89
                expanded: !this.state.expanded
90
            },
91
            () => {
92
                AttributeStore.set(
×
93
                    rjvId,
94
                    namespace,
95
                    'expanded',
96
                    this.state.expanded
97
                );
98
                if (typeof onToggleCollapse === 'function') {
×
99
                    onToggleCollapse({ expanded: this.state.expanded, name, namespace });
×
100
                }
101
            }
102
        );
103
    }
104

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

118
    getEllipsis = () => {
46✔
119
        const { size } = this.state;
15✔
120

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

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

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

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

159
        const IconComponent = expanded ? ExpandedIcon : CollapsedIcon;
52✔
160

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

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

201
        const { object_type, expanded } = this.state;
54✔
202

203
        let styles = {};
54✔
204
        if (!jsvRoot && parent_type !== 'array_group') {
54✔
205
            styles.paddingLeft = this.props.indentWidth * SINGLE_INDENT;
43✔
206
        } else if (parent_type === 'array_group') {
11✔
207
            styles.borderLeft = 0;
2✔
208
            styles.display = 'inline';
2✔
209
        }
210

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

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

261
        keys.forEach(name => {
39✔
262
            variable = new JsonVariable(name, variables[name]);
118✔
263

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

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

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

317
        return elements;
39✔
318
    };
319
}
320

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

330
polyfill(RjvObject);
1✔
331

332
//export component
333
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