Skip to content
This repository was archived by the owner on Apr 12, 2020. It is now read-only.

Commit 84da85d

Browse files
committed
initial commit
0 parents  commit 84da85d

File tree

7 files changed

+360
-0
lines changed

7 files changed

+360
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

README.md

Whitespace-only changes.

app.css

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#app-container {
2+
width: 960px;
3+
margin: 60px auto 0 auto;
4+
}
5+
6+
pre {
7+
background: black;
8+
color: #ddd;
9+
padding:4px;
10+
}
11+
12+
ul.answer-list li {
13+
margin-bottom: 1em;
14+
}
15+
16+
.survey, .question, .answer {
17+
margin-left:20px;
18+
}
19+
20+
.button-xsmall {
21+
font-size: 70%;
22+
}
23+
24+
.button-small {
25+
font-size: 85%;
26+
}
27+
28+
.button-large {
29+
font-size: 110%;
30+
}
31+
32+
.button-xlarge {
33+
font-size: 125%;
34+
}
35+
36+
.button-success,
37+
.button-error,
38+
.button-warning,
39+
.button-secondary {
40+
color: white;
41+
border-radius: 4px;
42+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
43+
}
44+
45+
.button-success {
46+
background: rgb(28, 184, 65); /* this is a green */
47+
}
48+
49+
.button-error {
50+
background: rgb(202, 60, 60); /* this is a maroon */
51+
}
52+
53+
.button-warning {
54+
background: rgb(223, 117, 20); /* this is an orange */
55+
}
56+
57+
.button-secondary {
58+
background: rgb(66, 184, 221); /* this is a light blue */
59+
}

index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang='en'>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>IMM</title>
6+
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.6.0/pure-min.css" />
7+
<link rel="stylesheet" href="app.css" />
8+
</head>
9+
<body>
10+
<div id='app-container'>
11+
<div id='app'></div>
12+
</div>
13+
14+
<script type="text/javascript" charset="utf-8" src='app.js'></script>
15+
<script src="https://use.fontawesome.com/66ded4eed4.js"></script>
16+
</body>
17+
</html>

js/app.jsx

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*global require*/
2+
"use strict";
3+
4+
var React = require('react');
5+
var ReactDOM = require('react-dom');
6+
var immstruct = require('immstruct');
7+
var Immutable = require('immutable');
8+
9+
document.addEventListener("DOMContentLoaded", function(event) {
10+
ReactDOM.render(
11+
<App />,
12+
document.getElementById('app')
13+
);
14+
});
15+
16+
17+
var App = React.createClass({
18+
getInitialState: function(){
19+
var structure = immstruct('survey-data', { newSurveyName: '', surveys: [] });
20+
structure.on('swap', function (newStructure, oldStructure, keyPath) {
21+
this.setState({ cursor: immstruct('survey-data').cursor() });
22+
}.bind(this));
23+
return {
24+
cursor: structure.cursor(),
25+
newSurveyName: '',
26+
};
27+
},
28+
29+
updateNewSurveyName: function(e) {
30+
this.state.cursor.cursor('newSurveyName').update(function(){
31+
return e.target.value;
32+
}.bind(this));
33+
},
34+
35+
createSurvey: function(e) {
36+
e.preventDefault();
37+
var name = this.state.cursor.cursor('newSurveyName').deref().trim();
38+
if (name) {
39+
this.state.cursor.cursor('surveys').update(function(surveys){
40+
var s = surveys.push(Immutable.fromJS({ name: name, questions: [] }));
41+
return s;
42+
}.bind(this));
43+
this.state.cursor.cursor('newSurveyName').update(function() {
44+
return '';
45+
});
46+
}
47+
},
48+
49+
removeSurvey: function(i) {
50+
this.state.cursor.cursor('surveys').delete(i);
51+
},
52+
53+
render: function(){
54+
return <div>
55+
<h1>Survery Builder</h1>
56+
<div className='pure-g'>
57+
<div className='pure-u-1-2'>
58+
<form className='pure-form' onSubmit={this.createSurvey}>
59+
<p>
60+
<button
61+
type='button'
62+
className='pure-button'
63+
placeholder='survey name'
64+
onClick={this.createSurvey}
65+
>
66+
<i className='fa fa-plus-circle'></i> Create Survey
67+
</button>
68+
{' '}
69+
<input
70+
type='text'
71+
id=''
72+
value={this.state.cursor.cursor('newSurveyName').deref()}
73+
onChange={this.updateNewSurveyName}
74+
/>
75+
</p>
76+
</form>
77+
78+
{this.state.cursor.cursor('surveys').toJS().map(function(s, i){
79+
return <Survey key={i} removeSurvey={this.removeSurvey.bind(this, i)} survey={this.state.cursor.cursor(['surveys', i])} />;
80+
}.bind(this))}
81+
</div>
82+
<div className='pure-u-1-2'>
83+
<pre>{JSON.stringify(this.state.cursor.toJS(), undefined, ' ')}</pre>
84+
</div>
85+
</div>
86+
</div>;
87+
}
88+
});
89+
90+
var Survey = React.createClass({
91+
shouldComponentUpdate: function(nextProps, nextState){
92+
return nextProps.survey.deref() !== this.props.survey.deref();
93+
},
94+
95+
createQuestion: function(e) {
96+
e.preventDefault();
97+
var name = this.props.survey.cursor('newQuestion').deref();
98+
if (name) {
99+
this.props.survey.cursor('questions').update(function(questions){
100+
var q = Immutable.fromJS({name: name, newAnswer: '', answers: [] });
101+
return questions.push(q);
102+
}.bind(this));
103+
this.props.survey.cursor('newQuestion').update(function() {
104+
return '';
105+
});
106+
}
107+
},
108+
109+
removeQuestion: function(i) {
110+
this.props.survey.cursor('questions').delete(i);
111+
},
112+
113+
updateNewQuestion: function(e) {
114+
this.props.survey.cursor('newQuestion').update(function(){
115+
return e.target.value;
116+
}.bind(this));
117+
},
118+
119+
render: function() {
120+
var s = this.props.survey;
121+
console.log('render survey', s.cursor('name').deref());
122+
console.log('rendering survey');
123+
return <div className='survey'>
124+
<h3>
125+
Survey: {s.cursor('name').deref()}
126+
</h3>
127+
<p>
128+
<button type='button' className='pure-button button-error button-xsmall' onClick={this.props.removeSurvey}>
129+
<i className='fa fa-minus-circle'></i> Remove Survey
130+
</button>
131+
</p>
132+
<form className='pure-form' onSubmit={this.createQuestion}>
133+
<button className='pure-button' type='button' onClick={this.createQuestion}>
134+
<i className='fa fa-plus-circle'></i> Create Question
135+
</button>
136+
{' '}
137+
<input
138+
type='text'
139+
id=''
140+
value={s.cursor('newQuestion').deref() || ''}
141+
onChange={this.updateNewQuestion}
142+
placeholder='question'
143+
/>
144+
</form>
145+
{this.props.survey.cursor('questions').toJS().map(function(q, i){
146+
return <Question key={i} question={s.cursor(['questions', i])} removeQuestion={this.removeQuestion.bind(this, i)} />;
147+
}.bind(this))}
148+
</div>;
149+
}
150+
});
151+
152+
var Question = React.createClass({
153+
shouldComponentUpdate: function(nextProps, nextState){
154+
return nextProps.question.deref() !== this.props.question.deref();
155+
},
156+
157+
updateAnswer: function(e) {
158+
this.props.question.cursor('newAnswer').update(function(){
159+
return e.target.value;
160+
});
161+
},
162+
163+
createAnswer: function(e) {
164+
e.preventDefault();
165+
166+
var q = this.props.question;
167+
var name = q.cursor('newAnswer').deref().trim();
168+
169+
if (name) {
170+
q.cursor('answers').update(function(answers) {
171+
return answers.push(Immutable.fromJS({name: name }));
172+
});
173+
q.cursor('newAnswer').update(function(){
174+
return '';
175+
});
176+
}
177+
},
178+
179+
removeAnswer: function(i, e) {
180+
this.props.question.cursor('answers').update(function(answers){
181+
return answers.delete(i);
182+
}.bind(this));
183+
},
184+
185+
render: function() {
186+
var q = this.props.question;
187+
console.log('render question', q.cursor('name').deref());
188+
var answers = q.cursor('answers').toJS() || [];
189+
return <div className='question'>
190+
<h4>Question: {q.cursor('name').deref()}</h4>
191+
<p>
192+
<button type='button' className='pure-button button-error button-xsmall' onClick={this.props.removeQuestion}>
193+
<i className='fa fa-minus-circle'></i> Remove Question
194+
</button>
195+
</p>
196+
<form onSubmit={this.createAnswer} className='pure-form'>
197+
<button type='submit' className='pure-button'>
198+
<i className='fa fa-plus-circle'></i> Add Answer
199+
</button>
200+
{' '}
201+
<input
202+
type='text'
203+
id=''
204+
value={q.cursor('newAnswer').deref() || ''}
205+
onChange={this.updateAnswer}
206+
placeholder='new answer'
207+
/>
208+
</form>
209+
<ul className='answer-list'>
210+
{answers.map(function(a, i){
211+
return <li key={i}>
212+
<button type='button' className='pure-button button-xsmall button-error' onClick={this.removeAnswer.bind(this, i)}>
213+
<i className='fa fa-minus-circle'></i> Remove
214+
</button>
215+
{' '}
216+
<Answer answer={q.cursor(['answers', i])} />
217+
</li>;
218+
}.bind(this))}
219+
</ul>
220+
</div>;
221+
}
222+
});
223+
224+
var Answer = React.createClass({
225+
shouldComponentUpdate: function(nextProps, nextState){
226+
return nextProps.answer.deref() !== this.props.answer.deref();
227+
},
228+
229+
render: function() {
230+
console.log('render answer', this.props.answer.cursor('name').deref());
231+
return <span>
232+
{this.props.answer.cursor('name').deref()}
233+
</span>;
234+
}
235+
});

package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "imm",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"private": true,
7+
"scripts": {
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
},
10+
"author": "",
11+
"license": "ISC",
12+
"devDependencies": {
13+
"babel-core": "^6.8.0",
14+
"babel-loader": "^6.2.4",
15+
"babel-preset-es2015": "^6.6.0",
16+
"immstruct": "^2.0.0",
17+
"immutable": "^3.8.1",
18+
"react": "^15.0.2",
19+
"webpack": "^1.13.0"
20+
},
21+
"dependencies": {
22+
"babel-core": "^6.8.0",
23+
"babel-loader": "^6.2.4",
24+
"babel-preset-react": "^6.5.0",
25+
"react": "^15.0.2",
26+
"react-dom": "^15.0.2"
27+
}
28+
}

webpack.config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*global module, __dirname*/
2+
"use strict";
3+
4+
module.exports = {
5+
  entry: './js/app.jsx',
6+
  output: { path: __dirname, filename: 'app.js' },
7+
  module: {
8+
    loaders: [
9+
{
10+
test: /.jsx?$/,
11+
loader: 'babel-loader',
12+
exclude: /node_modules/,
13+
query: {
14+
presets: ['es2015', 'react']
15+
}
16+
}
17+
]
18+
  },
19+
};
20+

0 commit comments

Comments
 (0)