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

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

pending completion
#1215

push

web-flow
Merge pull request #342 from mac-s-g/bump-patch

bump patch version

284 of 349 branches covered (81.38%)

Branch coverage included in aggregate %.

504 of 597 relevant lines covered (84.42%)

90.19 hits per line

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

89.21
/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;
2✔
24
//single indent is 5px
25
const SINGLE_INDENT = 5;
2✔
26

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

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

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

84
    toggleCollapsed = () => {
92✔
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) => {
92✔
101
        return (
78✔
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 = () => {
92✔
114
        const { size } = this.state;
30✔
115

116
        if (size === 0) {
30✔
117
            //don't render an ellipsis when an object has no items
118
            return null;
14✔
119
        } else {
120
            return (
16✔
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 => {
92✔
133
        const { rjvId, theme } = this.props;
108✔
134
        const { size, hovered } = this.state;
108✔
135
        return (
108✔
136
            <VariableMeta rowHovered={hovered} size={size} {...this.props} />
137
        );
138
    };
139

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

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

154
        const IconComponent = expanded ? ExpandedIcon : CollapsedIcon;
104✔
155

156
        return (
104✔
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' ? '[' : '{'}
104✔
173
                    </span>
174
                </span>
175
                {expanded ? this.getObjectMetaData(src) : null}
104✔
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;
108✔
195

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

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

206
        return (
108✔
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)}
108✔
216
            >
217
                {this.getBraceStart(object_type, expanded)}
218
                {expanded
108✔
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'
108✔
230
                        }}
231
                    >
232
                        {object_type === 'array' ? ']' : '}'}
108✔
233
                    </span>
234
                    {expanded ? null : this.getObjectMetaData(src)}
108✔
235
                </span>
236
            </div>
237
        );
238
    }
239

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

256
        keys.forEach(name => {
78✔
257
            variable = new JsonVariable(name, variables[name]);
236✔
258

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

279
                if (
26!
280
                    groupArraysAfterLength &&
46✔
281
                    variable.value.length > groupArraysAfterLength
282
                ) {
283
                    ObjectComponent = ArrayGroup;
×
284
                }
285

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

312
        return elements;
78✔
313
    };
314
}
315

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

325
polyfill(RjvObject);
2✔
326

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

© 2025 Coveralls, Inc