Skip to content
This repository has been archived by the owner on May 5, 2020. It is now read-only.

Commit

Permalink
support sending message arguments of different types - fixes #25
Browse files Browse the repository at this point in the history
  • Loading branch information
JoJordens committed Mar 6, 2018
1 parent 06b7679 commit c0917f8
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 42 deletions.
15 changes: 12 additions & 3 deletions socketTest/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ app.get('/', function(req, res){
res.sendFile(path.join(__dirname, 'index.html'));
});

function getTypeOf (value) {
return Object.prototype.toString.call(value).slice(8, -1)
}

io.on('connection', function(socket){
console.log('a user connected');
// socket.join('testRoom')
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('a', (msg) => {
console.log(msg)
console.log(Object.prototype.toString.apply(msg).slice(8, -1))
socket.on('a', function () {
console.log('all message arguments:', ...[].slice.call(arguments))
console.log('types', [].map.call(arguments, arg => getTypeOf(arg)))
})
socket.on('chat message', function(){
console.log('message:', ...[].slice.call(arguments));
Expand Down Expand Up @@ -44,6 +48,11 @@ function startIntervals () {
io.emit('test2', true);
}, 2000);

setInterval(function () {
x++;
io.emit('test5', true);
}, 5000);

setInterval(function () {
y++;
nsp.emit('test', 'nsp - message'+x);
Expand Down
7 changes: 7 additions & 0 deletions src/app/css/components/_column.scss
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@
.CodeMirror {
height: 200px;
}
&.red-border {
border-color: red;
}
}

.column-editor-no-border {
margin-bottom: 8px;
}

.column-block-group {
Expand Down
96 changes: 96 additions & 0 deletions src/app/js/components/column/messageSender/Editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { Component } from 'react'
import { Controlled as CodeMirror } from 'react-codemirror2'
import 'codemirror/mode/javascript/javascript'

const Editor = (props) => {
const type = props.message.type
let editor
switch (type) {
case 'String':
editor = <TextInput {...props} />
break

case 'Number':
editor = <NumberInput {...props} />
break

case 'Boolean':
editor = <BoolInput {...props} />
break

case 'JSON':
case 'Array':
case 'Object':
editor = <CodeMirrorInput {...props} />
break

default:
console.warn('unhandled message type', type)
editor = <p>unhandled message type {type}</p>
}
return editor
}

class TextInput extends Component {
render () {
const { message, handleMessageChange } = this.props
return (
<CodeMirror
className="column-editor"
value={message.value || ''}
onBeforeChange={ (editor, data, value) => handleMessageChange(value) }
/>
)
}
}

class NumberInput extends Component {
render () {
const { message, handleMessageChange } = this.props
return (
<div>
<label htmlFor="messageInput">Message: </label>
<input
className="column-editor"
id="messageInput"
type="number"
value={~~message.value}
onChange={ e => handleMessageChange(e.target.value) }
/>
</div>
)
}
}

class CodeMirrorInput extends Component {
render () {
const { message, handleMessageChange } = this.props
const isValid = message.isValid
return (
<div className={["column-editor", isValid ? "" : "red-border"].join(' ')}>
<CodeMirror
value={message.value || ''}
onBeforeChange={ (editor, data, value) => handleMessageChange(value) }
options={{mode: {name: 'javascript', json: true}}}
/>
</div>
)
}
}

class BoolInput extends Component {
render () {
const { message, handleMessageChange } = this.props
return (
<div className="column-editor-no-border">
<span>Boolean: </span>
<input onChange={ e => handleMessageChange('true') } checked={message.value === 'true'} id="boolTrue" type="radio" name="boolean" />
<label htmlFor="boolTrue">True</label>
<input onChange={ e => handleMessageChange('false') } checked={message.value === 'false'} id="boolFalse" type="radio" name="boolean" />
<label htmlFor="boolFalse">False</label>
</div>
)
}
}

export default Editor
148 changes: 111 additions & 37 deletions src/app/js/components/column/messageSender/MessageSenderView.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
*/

import React, { Component } from 'react'
import { Controlled as CodeMirror } from 'react-codemirror2'
import 'codemirror/mode/javascript/javascript'
import Autosuggest from 'react-autosuggest'
import Editor from './Editor'

// import TriangleBottomIcon from '../../../icons/TriangleBottom'

Expand All @@ -18,23 +17,22 @@ class MessageSender extends Component {
this.state = {
tab: this.getThisTab(props),
eventName: '',
messageCollection: [''],
messageCollection: [{type: 'String', value: '', isValid: true}],
messageInEditor: 0,
// message: '',
messageIsJson: false,
autosuggestResults: []
}

this.handleMessageSend = this.handleMessageSend.bind(this)
this.handleEventNameChange = this.handleEventNameChange.bind(this)
this.handleMessageBeforeChange = this.handleMessageBeforeChange.bind(this)
this.handleMessageChange = this.handleMessageChange.bind(this)
this.handleClearClick = this.handleClearClick.bind(this)
this.onSuggestionsFetchRequested = this.onSuggestionsFetchRequested.bind(this)
this.onSuggestionsClearRequested = this.onSuggestionsClearRequested.bind(this)
this.getSuggestionValue = this.getSuggestionValue.bind(this)
this.addMessageArgument = this.addMessageArgument.bind(this)
this.removeMessageArgument = this.removeMessageArgument.bind(this)
this.noMessageArgument = this.noMessageArgument.bind(this)
this.changeType = this.changeType.bind(this)
}

componentWillReceiveProps(nextProps) {
Expand Down Expand Up @@ -64,33 +62,107 @@ class MessageSender extends Component {
})
}

handleMessageBeforeChange (editor, data, value) {
/**
* Change message type and value if required
* @param {event} e - input change event
*/
changeType (e) {
const state = this.state
const messageCollection = state.messageCollection.slice()
messageCollection[state.messageInEditor] = value
const type = e.target.value
let isValid = true
let value = messageCollection[state.messageInEditor].value
switch ( type ) {
case 'Boolean':
value = 'true'
break

case 'Number':
value = ~~value
break

case 'Object':
case 'Array':
const parsedValue = this.testObjValid(value)
if ( parsedValue && Object.prototype.toString.apply(parsedValue).slice(8, -1) === type )
isValid = true
else
isValid = false
break

case 'String':
try { // stringify current value in case it's an object or it'll look like "[object Object]", if JSON.parse works it's already a string, so we don't need to change it
JSON.parse(value)
value = value + '' // convert boolean to string or codemirror throws an error
} catch ( e ) { // if it throws we know it's not a JSON string already and we have to stringify it
value = JSON.stringify(value)
}
break

case 'JSON':
try { // if JSON.parse works it's valid JSON
JSON.parse(value)
} catch ( e ) {
isValid = false
}
break
}
messageCollection[state.messageInEditor] = {
value,
type,
isValid
}
this.setState({
messageCollection,
messageIsJson: this.jsonOrText(value)
messageCollection
})
}

/**
* Returns true if string is valid JSON
*
* @param {String} string
*
* @return {Boolean}
* Update message and validation
*/
jsonOrText (string) {
let isJson
try {
JSON.parse(string)
isJson = true
handleMessageChange (value) {
const state = this.state
const messageCollection = state.messageCollection.slice()
const messageInEditor = state.messageInEditor
const message = messageCollection[messageInEditor]

const type = message.type
let isValid = message.isValid

switch ( type ) {
case 'Object':
case 'Array':
isValid = !!this.testObjValid(value)
break

case 'JSON':
try {
JSON.parse(value) // if it doesn't throw it's a valid JSON string
isValid = true
} catch ( e ) {
isValid = false
}
}
catch (error) {
isJson = false

messageCollection[messageInEditor] = {
value,
isValid,
type
}
return isJson
this.setState({
messageCollection
})
}

testObjValid (value) {
let evalResult, JSONResult
try {
eval(`evalResult = ${value}`) // if it doesn't throw it's a valid array or object
} catch ( e ) {}
try {
JSONResult = JSON.parse(value) // if it doesn't throw it's a valid array or object
} catch ( e ) {}
return evalResult || JSONResult
}

/**
Expand Down Expand Up @@ -164,7 +236,7 @@ class MessageSender extends Component {
addMessageArgument () {
const messageCollection = this.state.messageCollection
this.setState({
messageCollection: messageCollection.concat(''),
messageCollection: messageCollection.concat({type: 'String', value: '', isValid: true}),
messageInEditor: messageCollection.length
})
}
Expand Down Expand Up @@ -200,13 +272,18 @@ class MessageSender extends Component {
const state = this.state
const connected = state.tab.connected
const messageInEditor = state.messageInEditor
const messageInEditorObject = state.messageCollection[state.messageInEditor]

const autosuggestInputProps = {
placeholder: 'Event name',
value: state.eventName,
onChange: this.handleEventNameChange
};

let sendIsEnabled = true
if ( !connected || !state.eventName || !state.messageCollection.map( m => m.isValid ).reduce( (a, b) => a && b) )
sendIsEnabled = false

return (
<div className="column-block">
<h3 className="column-title">Send Message</h3>
Expand Down Expand Up @@ -274,12 +351,14 @@ class MessageSender extends Component {

<div className="column-string">
<span>
{
state.messageIsJson ?
"JSON"
:
"String"
}
<select value={messageInEditorObject.type} onChange={this.changeType}>
<option value="String">String</option>
<option value="JSON">JSON</option>
<option value="Array">Array</option>
<option value="Object">Object</option>
<option value="Number">Number</option>
<option value="Boolean">Boolean</option>
</select>
</span>
</div>

Expand All @@ -290,16 +369,11 @@ class MessageSender extends Component {
Clear
</button>

<CodeMirror
className="column-editor"
value={state.messageCollection[state.messageInEditor]}
onBeforeChange={this.handleMessageBeforeChange}
options={{mode: {name: 'javascript', json: true}}}
/>
<Editor message={messageInEditorObject} handleMessageChange={this.handleMessageChange} />

<button
className="column-button"
disabled={!connected}
disabled={!sendIsEnabled}
onClick={this.handleMessageSend}
>
Send message
Expand Down
1 change: 0 additions & 1 deletion src/app/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@ render(
</Provider>,
document.getElementById('app')
)

Loading

0 comments on commit c0917f8

Please sign in to comment.