<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap-css@3.3.1" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script data-require="react@*" data-semver="0.12.2" src="//cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.js"></script>
<script data-require="react-bootstrap@0.13.0" data-semver="0.13.0" src="//github.com/react-bootstrap/react-bootstrap/releases/download/v0.13.0/react-bootstrap.js"></script>
<script src="https://rawgit.com/rsamec/react-binding/master/dist/react-binding.min.js"></script>
<script src="https://rawgit.com/flesler/hashmap/master/hashmap.js"></script>
<script src="https://rawgit.com/rsamec/business-rules-engine/master/dist/business-rules-engine.js"></script>
<script data-require="underscore.js@1.6.0" data-semver="1.6.0" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script data-require="moment.js@2.8.3" data-semver="2.8.3" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.min.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="content"></div>
<script src="script.js"></script>
</body>
</html>
var Binder = Binder.default;
var dateConverter = function () {
this.parse = function (input, dateFormat) {
if (!!!input) return undefined;
if (input.length < 8) return undefined;
var date = moment(input, dateFormat);
if (date.isValid()) return date.toDate();
return undefined;
}
this.format = function (input, dateFormat) {
if (!!!input) return undefined;
return moment(input).format(dateFormat);
}
}
var ExampleForm = React.createClass({
getInitialState: function () {
var rulesDef = {
"Duration": {
"type": "object",
"properties": {
"From": {
"title": "From",
"required": "true",
"date": "true"
},
"To": {
"title": "From",
"required": "true",
"date": "true"
}
}
}
};
return {
data: {},
rules: new FormSchema.JsonSchemaRuleFactory(rulesDef).CreateRule("Main"),
datePickerFormat: 'DD.MM.YYYY'
};
},
validationResult: function () {
if (this.state.rules === undefined) return {Errors: {}};
return Utils.CompositeDotObject.Transform(this.state.rules.Validate(this.state.data)).Main;
},
duration: function () {
var dur = this.state.data.Duration;
if (dur === undefined || dur.From === undefined || dur.To === undefined) return;
return moment.duration(moment(dur.From).startOf('day').diff(moment(dur.To).startOf('day'))).humanize(); // 86400000
},
render: function () {
var formats = ['DD.MM.YYYY', 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD'];
var converter = new dateConverter();
return (
<div>
<div className="row">
<div className='col-md-2'>
<DatePicker label="From" model={Binder.bindToState(this,"data", "Duration.From", converter, this.state.datePickerFormat)} error={this.validationResult().Duration.From} />
<DatePicker label="To" model={Binder.bindToState(this,"data", "Duration.To", converter, this.state.datePickerFormat)} error={this.validationResult().Duration.To} />
<label>Duration:{this.duration()}</label>
</div>
<div className='col-md-2'>
<label>Format</label>
<Typeahead array={formats} placeholder="My Typeahead" model={Binder.bindToState(this,"datePickerFormat")} />
</div>
</div>
<div className="row">
<div className='col-md-4'>
<PrettyJson json={this.state.data} />
</div>
</div>
</div>
);
}
});
var PrettyJson = React.createClass({
replacer: function (match, pIndent, pKey, pVal, pEnd) {
var key = '<span class=json-key>';
var val = '<span class=json-value>';
var str = '<span class=json-string>';
var r = pIndent || '';
if (pKey)
r = r + key + pKey.replace(/[": ]/g, '') + '</span>: ';
if (pVal)
r = r + (pVal[0] == '"' ? str : val) + pVal + '</span>';
return r + (pEnd || '');
},
prettyPrint: function (obj) {
var jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg;
return JSON.stringify(obj, null, 3)
.replace(/&/g, '&').replace(/\\"/g, '"')
.replace(/</g, '<').replace(/>/g, '>')
.replace(jsonLine, this.replacer);
},
render: function () {
return (<pre dangerouslySetInnerHTML={{__html: this.prettyPrint(this.props.json)}}></pre>);
}
})
var DatePicker = React.createClass({
getInitialState: function () {
return {inputValue: undefined}
},
validationState: function(error) {
return error.HasErrors?'error':'';
},
formatValue: function (e) {
var valueModel = this.props.model;
//setter - calls converter.parse
valueModel.value = e.target.value;
this.setState({
typingFlag: false
});
},
render: function () {
var handleChange = function (e) {
this.setState({
inputValue: e.target.value,
typingFlag: true
});
}.bind(this);
var value = this.state.typingFlag ? this.state.inputValue : this.props.model.value;
//format manually
//var formatValue = function (e) {
// var parsedValue = converter.parse(e.target.value);
// valueModel.value = e.target.value;
// this.setState({inputValue:converter.format(parsedValue)});
//}.bind(this);
return (
<div style={{display: 'inline'}}>
<label style={{display: 'block'}}>{this.props.label}</label>
<ReactBootstrap.Input type='text' onChange={handleChange} onBlur={this.formatValue} value={value}
bsStyle={this.validationState(this.props.error)} help={this.props.error.ErrorMessage}/>
</div>
)
}
});
var CheckBoxInput = React.createClass({
render: function () {
var valueModel = this.props.model;
var handleChange = function (e) {
valueModel.value = e.target.checked;
}
return (
<label>
<input type='checkbox' onChange={handleChange} checked={valueModel.value} />
{this.props.label}
</label>
)
}
});
/**
* The MIT License (MIT)
Inspired by 2015 Pritesh Gupta
*/
var Typeahead = React.createClass({
getInitialState: function () {
return {value: '', index: -1, selected: true};
},
handleClick: function (e) {
this.props.model.value = e.target.innerHTML;
//debugger;
this.setState({selected: true});
},
selectItem: function (e) {
if (this.state.selected) return;
if (e.keyCode === 40 && this.state.index < this.items.length - 1) {
this.setState({index: ++this.state.index});
}
else if (e.keyCode === 38 && this.state.index > 0) {
this.setState({index: --this.state.index});
}
else if (e.keyCode === 13) {
this.props.model.value = this.items[this.state.index].key;
this.setState({selected: true, index: 0});
}
},
handleFocus: function (e) {
this.setState({selected: false});
},
//componentWillReceiveProps: function(nextProps) {
// this.setState({value: nextProps.value || '', index: -1, selected: true});
//},
render: function () {
this.items = [];
var valueModel = this.props.model;
var handleChange = function (e) {
valueModel.value = e.target.value;
this.setState({selected: false, index: 0});
}.bind(this);
var searchResult = this.state.selected || (
<div className="list-group typeahead">
{this.items}
</div>
);
var value = valueModel.value;
this.state.selected || this.props.array.filter(function (el) {
el = el.toLowerCase();
var val = value.toLowerCase();
return el.indexOf(val) > -1 || el.replace('-', ' ').indexOf(val) > -1;
}.bind(this)).every(function (el, idx) {
if (!value && idx > 9) return;
var className = this.state.index === idx ? 'list-group-item active' : 'list-group-item';
return this.items.push(<a key={el} className={className} onClick={this.handleClick}>{el}</a>);
}, this);
return (
<div className="field-group">
<input type="text" id={this.props.id} required className="form-control" value={valueModel.value} placeholder={this.props.placeholder}
onChange={handleChange} onKeyDown={this.selectItem} onFocus={this.handleFocus} />
{searchResult}
</div>
);
}
});
React.render(
<ExampleForm />,
document.getElementById('content')
);
/* Styles go here */
.error{
color: darkred;
}