diff --git a/dev-server/src/index.js b/dev-server/src/index.js index 58e2699..a7bc62d 100644 --- a/dev-server/src/index.js +++ b/dev-server/src/index.js @@ -180,6 +180,19 @@ ReactDom.render( } src={getExampleJson2()} /> + + {/* String with special escape sequences */} + { + console.log('edit callback', e) + if (e.new_value == 'error') { + return false + } + }} + /> , document.getElementById('app-container') ) @@ -189,7 +202,7 @@ ReactDom.render( /*-------------------------------------------------------------------------*/ //just a function to get an example JSON object -function getExampleJson1 () { +function getExampleJson1() { return { string: 'this is a test string', integer: 42, @@ -218,7 +231,7 @@ function getExampleJson1 () { } //and another a function to get an example JSON object -function getExampleJson2 () { +function getExampleJson2() { return { normalized: { '1-grams': { @@ -256,7 +269,7 @@ function getExampleJson2 () { } } -function getExampleJson3 () { +function getExampleJson3() { return { example_information: 'this example has the collapsed prop set to true and the indentWidth prop is set to 8', @@ -272,7 +285,7 @@ function getExampleJson3 () { } } -function getExampleJson4 () { +function getExampleJson4() { const large_array = new Array(225).fill('this is a large array full of items') large_array.push(getExampleArray()) @@ -282,7 +295,7 @@ function getExampleJson4 () { return large_array } -function getExampleArray () { +function getExampleArray() { return [ 'you can also display arrays!', new Date(), @@ -294,3 +307,7 @@ function getExampleArray () { } ] } + +function getExampleWithStringEscapeSequences() { + return { '\\\n\t\r\f\\n': '\\\n\t\r\f\\n' } +} diff --git a/src/js/components/DataTypes/String.js b/src/js/components/DataTypes/String.js index 29454e5..4faa1d8 100644 --- a/src/js/components/DataTypes/String.js +++ b/src/js/components/DataTypes/String.js @@ -1,6 +1,6 @@ import React from 'react' import DataTypeLabel from './DataTypeLabel' -import { toType } from './../../helpers/util' +import { toType, escapeString } from './../../helpers/util' // theme import Theme from './../../themes/getStyle' @@ -46,6 +46,8 @@ export default class extends React.PureComponent { const collapsible = toType(collapseStringsAfterLength) === 'integer' const style = { style: { cursor: 'default' } } + value = escapeString(value) + if (collapsible && value.length > collapseStringsAfterLength) { style.style.cursor = 'pointer' if (this.state.collapsed) { diff --git a/src/js/components/VariableEditor.js b/src/js/components/VariableEditor.js index 56cbb84..01b7cde 100644 --- a/src/js/components/VariableEditor.js +++ b/src/js/components/VariableEditor.js @@ -1,7 +1,7 @@ import React from 'react' import AutosizeTextarea from 'react-textarea-autosize' -import { toType } from './../helpers/util' +import { escapeString } from './../helpers/util' import dispatcher from './../helpers/dispatcher' import parseInput from './../helpers/parseInput' import stringifyVariable from './../helpers/stringifyVariable' @@ -93,7 +93,7 @@ class VariableEditor extends React.PureComponent { {!!quotesOnKeys && ( " )} - {variable.name} + {escapeString(variable.name)} {!!quotesOnKeys && ( " )} diff --git a/src/js/helpers/util.js b/src/js/helpers/util.js index a11ea83..6654f8a 100644 --- a/src/js/helpers/util.js +++ b/src/js/helpers/util.js @@ -23,6 +23,15 @@ function getType (obj) { .toLowerCase() } +export function escapeString (value) { + return value + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\t/g, '\\t') + .replace(/\r/g, '\\r') + .replace(/\f/g, '\\f') +} + // validation for base-16 themes export function isTheme (theme) { const theme_keys = [ diff --git a/test/tests/js/components/DataTypes/String-test.js b/test/tests/js/components/DataTypes/String-test.js index 1ef0a47..41baea6 100644 --- a/test/tests/js/components/DataTypes/String-test.js +++ b/test/tests/js/components/DataTypes/String-test.js @@ -61,4 +61,18 @@ describe('', function () { '"123456789"' ) }) + + it('string with special escape sequences', function () { + const rjvId = 1 + const props = { + value: '\\\n\t\r\f\\n', + rjvId: 1, + displayDataTypes: false, + theme: 'rjv-default' + } + const component = mount().render() + expect(component.find('.string-value').text()).to.equal( + '"\\\\\\n\\t\\r\\f\\\\n"' + ) + }) }) diff --git a/test/tests/js/components/VariableEditor-test.js b/test/tests/js/components/VariableEditor-test.js index fe5c100..9d1f57c 100644 --- a/test/tests/js/components/VariableEditor-test.js +++ b/test/tests/js/components/VariableEditor-test.js @@ -13,7 +13,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} singleIndent={1} variable={{ @@ -48,7 +48,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -66,7 +66,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -172,7 +172,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -192,7 +192,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -212,7 +212,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -232,7 +232,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -252,7 +252,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -274,7 +274,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -294,7 +294,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -314,7 +314,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -334,7 +334,7 @@ describe('', function () { {}} + onEdit={edit => { }} rjvId={rjvId} variable={{ name: 'test', @@ -348,4 +348,28 @@ describe('', function () { expect(wrapper.state('editMode')).to.equal(true) expect(wrapper.find('.variable-editor').props().value).to.equal('5') }) + + it('VariableEditor renders escaped characters', function () { + const wrapper = shallow( + { }} + rjvId={rjvId} + variable={{ + name: '\\\n\t\r\f\\n', + value: '\\\n\t\r\f\\n', + type: 'string' + }} + /> + ) + console.log(wrapper.debug()) + expect(wrapper.find('.object-key').text()).to.equal('\\\\\\n\\t\\r\\f\\\\n') + expect(wrapper.find('.click-to-edit-icon').length).to.equal(1) + wrapper.find('.click-to-edit-icon').simulate('click') + expect(wrapper.state('editMode')).to.equal(true) + expect(wrapper.find('.variable-editor').props().value).to.equal( + '\\\n\t\r\f\\n' + ) + }) }) diff --git a/test/tests/js/helpers/Util-test.js b/test/tests/js/helpers/Util-test.js index fce258d..19d51ba 100644 --- a/test/tests/js/helpers/Util-test.js +++ b/test/tests/js/helpers/Util-test.js @@ -1,7 +1,7 @@ import React from 'react' import { expect } from 'chai' -import { toType, isTheme } from './../../../../src/js/helpers/util' +import { toType, isTheme, escapeString } from './../../../../src/js/helpers/util' describe('toType', function () { it('toType object', function () { @@ -30,7 +30,7 @@ describe('toType', function () { }) it('toType function', function () { - const test = () => {} + const test = () => { } expect(toType(test)).to.equal('function') }) @@ -60,6 +60,33 @@ describe('toType', function () { }) }) +describe('escapeString', function () { + it('escape \\\\', function () { + const test = '\\' + expect(escapeString(test)).to.equal('\\\\') + }) + it('escape \\n', function () { + const test = '\n' + expect(escapeString(test)).to.equal('\\n') + }) + it('escape \\t', function () { + const test = '\t' + expect(escapeString(test)).to.equal('\\t') + }) + it('escape \\r', function () { + const test = '\r' + expect(escapeString(test)).to.equal('\\r') + }) + it('escape \\f', function () { + const test = '\f' + expect(escapeString(test)).to.equal('\\f') + }) + it('escape \\\\n', function () { + const test = '\\n' + expect(escapeString(test)).to.equal('\\\\n') + }) +}) + describe('isTheme', function () { it('isTheme valid theme', function () { const test = {