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

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

18 Mar 2024 12:10PM UTC coverage: 15.895% (-67.8%) from 83.718%
#2828

push

loredanacirstea
1.21.6

57 of 368 branches covered (15.49%)

Branch coverage included in aggregate %.

101 of 626 relevant lines covered (16.13%)

0.85 hits per line

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

2.82
/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);
×
30
        const state = RjvObject.getState(props);
×
31
        this.state = {
×
32
            ...state,
33
            prevProps: {}
34
        };
35
    }
36

37
    static getState = props => {
1✔
38
        const size = Object.keys(props.src).length;
×
39
        const expanded =
40
            (props.collapsed === false ||
×
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 = {
×
52
            expanded: AttributeStore.get(
53
                props.rjvId,
54
                props.namespace,
55
                'expanded',
56
                expanded
57
            ),
58
            object_type: props.type === 'array' ? 'array' : 'object',
×
59
            parent_type: props.type === 'array' ? 'array' : 'object',
×
60
            size,
61
            hovered: false
62
        };
63
        return state;
×
64
    };
65

66
    static getDerivedStateFromProps(nextProps, prevState) {
67
        const { prevProps } = prevState;
×
68
        if (
×
69
            nextProps.src !== prevProps.src ||
×
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);
×
76
            return {
×
77
                ...newState,
78
                prevProps: nextProps
79
            };
80
        }
81
        return null;
×
82
    }
83

84
    toggleCollapsed = () => {
×
85
        this.setState(
×
86
            {
87
                expanded: !this.state.expanded
88
            },
89
            () => {
90
                AttributeStore.set(
×
91
                    this.props.rjvId,
92
                    this.props.namespace,
93
                    'expanded',
94
                    this.state.expanded
95
                );
96
            }
97
        );
98
    };
99

100
    getObjectContent = (depth, src, props) => {
×
101
        return (
×
102
            <div class="pushed-content object-container">
103
                <div
104
                    class="object-content"
105
                    {...Theme(this.props.theme, 'pushed-content')}
106
                >
107
                    {this.renderObjectContents(src, props)}
108
                </div>
109
            </div>
110
        );
111
    };
112

113
    getEllipsis = () => {
×
114
        const { size } = this.state;
×
115

116
        if (size === 0) {
×
117
            //don't render an ellipsis when an object has no items
118
            return null;
×
119
        } else {
120
            return (
×
121
                <div
122
                    {...Theme(this.props.theme, 'ellipsis')}
123
                    class="node-ellipsis"
124
                    onClick={this.toggleCollapsed}
125
                >
126
                    ...
127
                </div>
128
            );
129
        }
130
    };
131

132
    getObjectMetaData = src => {
×
133
        const { rjvId, theme, customButtons } = this.props;
×
134
        const { size, hovered } = this.state;
×
135
        return (
×
136
            <VariableMeta customButtons={customButtons} rowHovered={hovered} size={size} {...this.props} />
137
        );
138
    };
139

140
    getBraceStart(object_type, expanded) {
141
        const { src, theme, iconStyle, parent_type } = this.props;
×
142

143
        if (parent_type === 'array_group') {
×
144
            return (
×
145
                <span>
146
                    <span {...Theme(theme, 'brace')}>
147
                        {object_type === 'array' ? '[' : '{'}
×
148
                    </span>
149
                    {expanded ? this.getObjectMetaData(src) : null}
×
150
                </span>
151
            );
152
        }
153

154
        const IconComponent = expanded ? ExpandedIcon : CollapsedIcon;
×
155

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

180
    render() {
181
        // `indentWidth` and `collapsed` props will
182
        // perpetuate to children via `...rest`
183
        const {
184
            depth,
185
            src,
186
            namespace,
187
            name,
188
            type,
189
            parent_type,
190
            theme,
191
            jsvRoot,
192
            iconStyle,
193
            ...rest
194
        } = this.props;
×
195

196
        const { object_type, expanded } = this.state;
×
197

198
        let styles = {};
×
199
        if (!jsvRoot && parent_type !== 'array_group') {
×
200
            styles.paddingLeft = this.props.indentWidth * SINGLE_INDENT;
×
201
        } else if (parent_type === 'array_group') {
×
202
            styles.borderLeft = 0;
×
203
            styles.display = 'inline';
×
204
        }
205

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

240
    renderObjectContents = (variables, props) => {
×
241
        const {
242
            depth,
243
            parent_type,
244
            index_offset,
245
            groupArraysAfterLength,
246
            namespace
247
        } = this.props;
×
248
        const { object_type } = this.state;
×
249
        let elements = [],
×
250
            variable;
251
        let keys = Object.keys(variables || {});
×
252
        if (this.props.sortKeys && object_type !== 'array') {
×
253
            keys = keys.sort();
×
254
        }
255

256
        keys.forEach(name => {
×
257
            variable = new JsonVariable(name, variables[name]);
×
258
            if (name === 'rowConfig') return;
×
259

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

280
                if (
×
281
                    groupArraysAfterLength &&
×
282
                    variable.value.length > groupArraysAfterLength
283
                ) {
284
                    ObjectComponent = ArrayGroup;
×
285
                }
286

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

313
        return elements;
×
314
    };
315
}
316

317
//just store name, value and type with a variable
318
class JsonVariable {
319
    constructor(name, value) {
320
        this.name = name;
×
321
        this.value = value;
×
322
        this.type = toType(value);
×
323
    }
324
}
325

326
polyfill(RjvObject);
1✔
327

328
//export component
329
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