Skip to content

Commit

Permalink
Better date/time handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
ledsoft committed Aug 24, 2016
1 parent 7d5aca2 commit d9c8d0e
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 142 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "semforms",
"version": "0.0.4",
"version": "0.0.5",
"description": "Semantic forms generator and processor",
"keywords": [
"react",
Expand All @@ -21,7 +21,8 @@
"dependencies": {
"react-bootstrap": "^0.28.5",
"object-assign": "^4.1.0",
"jsonld": "~0.4.6",
"jsonld": "^0.4.6",
"moment": "^2.14.1",
"kbss-react-bootstrap-datetimepicker": "https://dev.inbas.cz/dist/kbss-react-bootstrap-datetimepicker-0.0.4.tgz",
"react-bootstrap-typeahead": "https://dev.inbas.cz/dist/react-bootstrap-typeahead-0.0.7.tgz",
"jsonld-utils": "https://kbss.felk.cvut.cz/dist/jsonld-utils-0.0.2.tgz"
Expand Down
149 changes: 17 additions & 132 deletions src/components/Answer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import React from "react";
import assign from "object-assign";
import DateTimePicker from "kbss-react-bootstrap-datetimepicker";
import CheckboxAnswer from "./answer/CheckboxAnswer";
import DateTimeAnswer from "./answer/DateTimeAnswer";
import InputAnswer from "./answer/InputAnswer";
import JsonldUtils from "jsonld-utils";
import Typeahead from "react-bootstrap-typeahead";
import Configuration from "../model/Configuration";
import Constants from "../constants/Constants";
import SelectAnswer from "./answer/SelectAnswer";
import FormUtils from "../util/FormUtils";
import Utils from "../util/Utils";
import TypeaheadAnswer from "./answer/TypeaheadAnswer";

export default class Answer extends React.Component {
static propTypes = {
Expand All @@ -20,55 +22,11 @@ export default class Answer extends React.Component {

constructor(props) {
super(props);
if (FormUtils.isTypeahead(this.props.question)) {
this._queryHash = Utils.getStringHash(FormUtils.getPossibleValuesQuery(this.props.question));
}
this.state = {
options: this._queryHash ? JsonldUtils.processTypeaheadOptions(Configuration.optionsStore.getOptions(this._queryHash)) : []
}
}

componentWillMount() {
var question = this.props.question;
if (FormUtils.isTypeahead(question)) {
if (!question[Constants.HAS_OPTION] && FormUtils.getPossibleValuesQuery(question)) {
Configuration.actions.loadFormOptions(this._queryHash, FormUtils.getPossibleValuesQuery(question));
} else {
this.setState({options: JsonldUtils.processTypeaheadOptions(question[Constants.HAS_OPTION])});
}
}
}

componentDidMount() {
this.unsubscribe = Configuration.optionsStore.listen(this._onOptionsLoaded);
}

componentWillUnmount() {
this.unsubscribe();
}

_onOptionsLoaded = (type, options) => {
if (type !== this._queryHash) {
return;
}
options = JsonldUtils.processTypeaheadOptions(options);
var value = FormUtils.resolveValue(this.props.answer),
selected = options.find((item) => {
return item.id === value;
});
this.setState({options: options});
this.refs.typeahead.selectOption(selected);
};

onCheckboxToggle = (e) => {
onValueChange = (value) => {
var change = assign({}, this.props.answer);
this._setValue(change, e.target.checked);
this.props.onChange(this.props.index, change);
};

onChange = (e) => {
var change = assign({}, this.props.answer);
this._setValue(change, e.target.value);
this._setValue(change, value);
this.props.onChange(this.props.index, change);
};

Expand All @@ -84,12 +42,6 @@ export default class Answer extends React.Component {
}
}

_onOptionSelected = (option) => {
var change = assign({}, this.props.answer);
this._setValue(change, option.id);
this.props.onChange(this.props.index, change);
};


render() {
var question = this.props.question,
Expand All @@ -116,95 +68,28 @@ export default class Answer extends React.Component {
return item[Constants.HAS_OPTION] && item[Constants.HAS_OPTION].length !== 0;
}

_generateSelectOptions(options) {
var rendered = [];
options.sort(function (a, b) {
var aLabel = JsonldUtils.getJsonAttValue(a, JsonldUtils.RDFS_LABEL),
bLabel = JsonldUtils.getJsonAttValue(b, JsonldUtils.RDFS_LABEL);
if (aLabel < bLabel) {
return -1;
}
if (aLabel > bLabel) {
return 1;
}
return 0;
});
for (var i = 0, len = options.length; i < len; i++) {
rendered.push(<option value={JsonldUtils.getJsonAttValue(options[i], JsonldUtils.RDFS_LABEL)}
key={'opt-' + i}>{JsonldUtils.getJsonAttValue(options[i], JsonldUtils.RDFS_LABEL)}</option>);
}
return rendered;
}

_renderTypeahead(value, label, title) {
value = Utils.idToName(this.state.options, value);
var question = this.props.question,
inputProps = {
disabled: FormUtils.isDisabled(question)
};
return <div>
<label className='control-label'>{label}</label>
<Typeahead ref='typeahead' className='form-group form-group-sm' formInputOption='id'
inputProps={inputProps}
title={title} value={value} label={label} placeholder={label} filterOption='name'
displayOption='name' onOptionSelected={this._onOptionSelected} optionsButton={true}
options={this.state.options} customListComponent={Configuration.typeaheadResultList}/>
</div>;
return <TypeaheadAnswer question={this.props.question} answer={this.props.answer} label={label} title={title}
value={value} onChange={this.onValueChange}/>;
}

_renderSelect(value, label, title) {
var question = this.props.question;
component = React.createElement(Configuration.inputComponent, {
type: 'select',
label: label,
value: value,
title: title,
onChange: this.onChange,
disabled: FormUtils.isDisabled(question)
}, this._generateSelectOptions(question[Constants.HAS_OPTION])
);
return <SelectAnswer question={this.props.question} label={label} title={title} value={value}
onChange={this.onValueChange}/>;
}

_renderDateTimePicker(value, label, title) {
var question = this.props.question,
mode = Utils.resolveDateTimeMode(question);
return <div style={{position: 'relative'}}>
<label className='control-label'>{label}</label>
<DateTimePicker mode={mode} inputFormat={Configuration.dateTimeFormat ? Configuration.dateTimeFormat : null}
inputProps={{title: title, bsSize: 'small'}}
onChange={this.onChange} dateTime={value}/>
</div>
return <DateTimeAnswer question={this.props.question} value={value} title={title} label={label}
onChange={this.onValueChange}/>;
}

_renderCheckbox(value, label, title) {
var question = this.props.question;
return React.createElement(Configuration.inputComponent, {
type: 'checkbox',
label: label,
title: title,
checked: value,
onChange: this.onCheckboxToggle,
disabled: FormUtils.isDisabled(question),
});
return <CheckboxAnswer label={label} title={title} value={value} onChange={this.onValueChange}
question={this.props.question}/>;
}

_renderRegularInput(value, label, title) {
var question = this.props.question,
answer = this.props.answer;
// When the value is an object_value, but the layout does not specify neither typeahead nor select,
// show at least the value's label
if (answer[Constants.HAS_OBJECT_VALUE] && answer[Constants.HAS_OBJECT_VALUE][JsonldUtils.RDFS_LABEL]) {
value = JsonldUtils.getJsonAttValue(answer[Constants.HAS_OBJECT_VALUE], JsonldUtils.RDFS_LABEL);
}
var inputType = FormUtils.isTextarea(question, value) ? 'textarea' : 'text';
return React.createElement(Configuration.inputComponent, {
type: inputType,
label: label,
title: title,
value: value,
onChange: this.onChange,
disabled: FormUtils.isDisabled(question),
rows: 5
});
return <InputAnswer question={this.props.question} answer={this.props.answer} label={label} title={title}
value={value} onChange={this.onValueChange}/>;
}
}
30 changes: 30 additions & 0 deletions src/components/answer/CheckboxAnswer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

import React from 'react';

import Configuration from '../../model/Configuration';
import FormUtils from '../../util/FormUtils';

const CheckboxAnswer = (props) => {
var question = props.question;
return React.createElement(Configuration.inputComponent, {
type: 'checkbox',
label: props.label,
title: props.title,
checked: props.value === true || props.value === 'true',
onChange: (e) => {
props.onChange(e.target.checked);
},
disabled: FormUtils.isDisabled(question),
});
};

CheckboxAnswer.propTypes = {
question: React.PropTypes.object.isRequired,
label: React.PropTypes.string.isRequired,
title: React.PropTypes.string,
value: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.bool]),
onChange: React.PropTypes.func.isRequired
};

export default CheckboxAnswer;
33 changes: 33 additions & 0 deletions src/components/answer/DateTimeAnswer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

import React from "react";
import moment from "moment";
import DateTimePicker from "kbss-react-bootstrap-datetimepicker";
import Configuration from "../../model/Configuration";
import Utils from "../../util/Utils";

const DateTimeAnswer = (props) => {
var mode = Utils.resolveDateTimeMode(props.question),
value = Utils.resolveDateTimeValue(props.question, props.value);
if (!value.isValid()) {
value = moment();
}
return <div style={{position: 'relative'}}>
<label className='control-label'>{props.label}</label>
<DateTimePicker mode={mode} inputFormat={Configuration.dateTimeFormat}
inputProps={{title: props.title, bsSize: 'small'}}
onChange={(date) => {
props.onChange(Number(date))
}} dateTime={value.format(Configuration.dateTimeFormat)}/>
</div>
};

DateTimeAnswer.propTypes = {
question: React.PropTypes.object.isRequired,
label: React.PropTypes.string.isRequired,
title: React.PropTypes.string,
value: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired
};

export default DateTimeAnswer;
42 changes: 42 additions & 0 deletions src/components/answer/InputAnswer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict';

import React from 'react';
import JsonLdUtils from 'jsonld-utils';

import Configuration from '../../model/Configuration';
import Constants from '../../constants/Constants';
import FormUtils from '../../util/FormUtils';

const InputAnswer = (props) => {
var question = props.question,
answer = props.answer,
value = props.value;
// When the value is an object_value, but the layout does not specify neither typeahead nor select,
// show at least the value's label
if (answer[Constants.HAS_OBJECT_VALUE] && answer[Constants.HAS_OBJECT_VALUE][JsonLdUtils.RDFS_LABEL]) {
value = JsonLdUtils.getJsonAttValue(answer[Constants.HAS_OBJECT_VALUE], JsonLdUtils.RDFS_LABEL);
}
var inputType = FormUtils.isTextarea(question, value) ? 'textarea' : 'text';
return React.createElement(Configuration.inputComponent, {
type: inputType,
label: props.label,
title: props.title,
value: value,
onChange: (e) => {
props.onChange(e.target.value)
},
disabled: FormUtils.isDisabled(question),
rows: 5
});
};

InputAnswer.propTypes = {
question: React.PropTypes.object.isRequired,
answer: React.PropTypes.object.isRequired,
label: React.PropTypes.string.isRequired,
title: React.PropTypes.string,
value: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired
};

export default InputAnswer;
54 changes: 54 additions & 0 deletions src/components/answer/SelectAnswer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict';

import React from 'react';
import JsonLdUtils from 'jsonld-utils';

import Configuration from '../../model/Configuration';
import Constants from '../../constants/Constants';
import FormUtils from '../../util/FormUtils';

export default class SelectAnswer extends React.Component {
static propTypes = {
question: React.PropTypes.object.isRequired,
label: React.PropTypes.string.isRequired,
title: React.PropTypes.string,
value: React.PropTypes.string,
onChange: React.PropTypes.func.isRequired
};

constructor(props) {
super(props);
}

_generateSelectOptions(options) {
var rendered = [];
options.sort(function (a, b) {
var aLabel = JsonLdUtils.getJsonAttValue(a, JsonldUtils.RDFS_LABEL),
bLabel = JsonLdUtils.getJsonAttValue(b, JsonldUtils.RDFS_LABEL);
if (aLabel < bLabel) {
return -1;
}
if (aLabel > bLabel) {
return 1;
}
return 0;
});
for (var i = 0, len = options.length; i < len; i++) {
rendered.push(<option value={JsonLdUtils.getJsonAttValue(options[i], JsonldUtils.RDFS_LABEL)}
key={'opt-' + i}>{JsonLdUtils.getJsonAttValue(options[i], JsonldUtils.RDFS_LABEL)}</option>);
}
return rendered;
}

render() {
return React.createElement(Configuration.inputComponent, {
type: 'select',
label: this.props.label,
value: this.props.value,
title: this.props.title,
onChange: (e) => {this.props.onChange(e.target.value)},
disabled: FormUtils.isDisabled(question)
}, this._generateSelectOptions(question[Constants.HAS_OPTION])
);
}
}

0 comments on commit d9c8d0e

Please sign in to comment.