Skip to content

Commit

Permalink
Render type question tree select
Browse files Browse the repository at this point in the history
  • Loading branch information
holubv committed May 1, 2021
1 parent b31c840 commit 7eb8685
Show file tree
Hide file tree
Showing 8 changed files with 429 additions and 124 deletions.
227 changes: 171 additions & 56 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "s-forms-smart-components",
"version": "0.0.5",
"version": "0.0.6",
"private": true,
"scripts": {
"dev": "parcel serve ./test/index.html --port 8080",
Expand All @@ -24,7 +24,9 @@
"src/",
"dist/"
],
"dependencies": {},
"dependencies": {
"intelligent-tree-select": "^0.8.0"
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-export-default-from": "^7.8.3",
Expand All @@ -40,6 +42,6 @@
"react": "~16.9.0",
"react-bootstrap": "1.0.1",
"react-dom": "~16.9.0",
"s-forms": "https://kbss.felk.cvut.cz/dist/s-forms-0.2.5.tgz"
"s-forms": "https://kbss.felk.cvut.cz/dist/s-forms-0.2.6.tgz"
}
}
1 change: 1 addition & 0 deletions src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export default class Constants {
static SHOW_ADVANCED_QUESTION = 'http://onto.fel.cvut.cz/ontologies/form/show-advanced-question';
static HAS_UNIT_OF_MEASURE = 'http://onto.fel.cvut.cz/ontologies/form/has-unit-of-measure-question';

static LAYOUT_TYPE_QUESTION = 'type-question';
}
27 changes: 21 additions & 6 deletions src/components/AnswerableSectionComposite.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React from 'react';
import {Accordion, Card, Form} from 'react-bootstrap';
import JsonLdUtils from 'jsonld-utils';
import {Question, FormUtils, Constants as SConstants, HelpIcon, Answer, ConfigurationContext} from 's-forms';
import {Question, FormUtils, Constants as SConstants, Answer, ConfigurationContext} from 's-forms';
import Constants from "../Constants";
import classNames from 'classnames';
import JsonldUtils from 'jsonld-utils';
import SmartComponents from "../SmartComponents";
import {QuestionWithAdvanced} from "../lib";
import QuestionWithAdvanced from "./QuestionWithAdvanced";
import TypeQuestionAnswer from "./TypeQuestionAnswer";

export default class AnswerableSectionComposite extends Question {

Expand All @@ -31,6 +29,23 @@ export default class AnswerableSectionComposite extends Question {
);
}

_renderAnswer(index, answer) {
const question = this.props.question;

let component = Answer;

if (TypeQuestionAnswer.mappingRule(question)) {
component = TypeQuestionAnswer;
}

return React.createElement(component, {
index: index,
answer: answer,
question: question,
onChange: this.onAnswerChange
});
}

renderAnswers() {
const question = this.props.question,
children = [],
Expand All @@ -51,7 +66,7 @@ export default class AnswerableSectionComposite extends Question {
children.push(
<div key={'row-item-' + i} className={cls} id={question['@id']}>
<div className="answer-content" style={this._getAnswerWidthStyle()}>
<Answer index={i} answer={answers[i]} question={question} onChange={this.onAnswerChange}/>
{this._renderAnswer(i, answers[i])}
</div>
{this._renderUnits()}
{this._renderPrefixes()}
Expand Down
101 changes: 101 additions & 0 deletions src/components/TypeQuestionAnswer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';
import {Accordion, Card, Form, FormGroup} from 'react-bootstrap';
import JsonLdUtils from 'jsonld-utils';
import {
Question,
FormUtils,
Constants as SConstants,
HelpIcon,
Answer,
ConfigurationContext,
JsonLdObjectMap
} from 's-forms';
import Constants from "../Constants";
import SmartComponents from "../SmartComponents";
import PropTypes from "prop-types";
import {VirtualizedTreeSelect} from "intelligent-tree-select";

export default class TypeQuestionAnswer extends React.Component {

static mappingRule = q => JsonLdUtils.hasValue(q, SConstants.LAYOUT_CLASS, Constants.LAYOUT_TYPE_QUESTION);

constructor(props) {
super(props);

this.state = {
tree: [
{id: '1', value: '1', label: 'One', children: ['1-1', '1-2']},
{id: '1-1', value: '1-1', label: 'One One', children: []},
{id: '1-2', value: '1-2', label: 'One Two', children: []},
{id: '2', value: '2', label: 'Two', children: []},
],
selected: null
}
}

_onChange = value => {
console.log(value);

//console.log(JsonLdObjectMap.getObject('x:zvire'));

const change = { ...this.props.answer };

change[SConstants.HAS_DATA_VALUE] = {
'@value': !!(value && value.length)
};

this.setState({selected: value});
this.props.onChange(this.props.index, change);
}

_renderSelect() {

return (
<VirtualizedTreeSelect
value={this.state.selected}
valueKey="value"
labelKey="label"
childrenKey="children"
options={this.state.tree}
expanded={true}
closeOnSelect={false}
onChange={this._onChange}
// onChange={opt => {
// console.log(opt);
// this.setState({selected: opt.map(o => o.value).filter(v => v !== '1-1')});
//
// const tree = this.state.tree;
// tree[1].checked = false;
// tree[1].disabled = true;
// this.setState({tree: tree});
// }}
multi={true}
/>
);

}

_renderLabel() {
const label = JsonLdUtils.getLocalized(this.props.question[SConstants.RDFS_LABEL], this.context.options.intl);
return <Form.Label>{label}</Form.Label>;
}

render() {
return (
<div className="type-answer-group">
{this._renderLabel()}
{this._renderSelect()}
</div>
)
}

}

TypeQuestionAnswer.contextType = ConfigurationContext;

TypeQuestionAnswer.propTypes = {
index: PropTypes.number.isRequired,
answer: PropTypes.object.isRequired,
question: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired
}
29 changes: 29 additions & 0 deletions src/styles/components.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.answerable-section.accordion > .card {
overflow: visible;
}

.card-header.bg-primary .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #c6c6c6;
Expand Down Expand Up @@ -42,3 +46,28 @@
width: 240px;
margin-left: 20px;
}

.answerable-section > .card > .card-header .answer > .answer-content {
position: relative;
min-height: 24px;
}

.type-answer-group {
display: flex;
position: absolute;
width: 100%;
}

.type-answer-group .Select {
margin-top: -6px;
flex-grow: 1;
margin-left: 15px;
}

.type-answer-group .Select-control {
height: 37px;
}

.type-answer-group .Select--multi .Select-value {
margin-top: 4px;
}
119 changes: 60 additions & 59 deletions test/TestApp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ import SmartComponents from "../src/SmartComponents";
import 's-forms/css/s-forms.min.css';
import '../src/styles/components.css';
import 'react-datepicker/dist/react-datepicker.css';
import "intelligent-tree-select/lib/styles.css"

const componentMapping = SmartComponents.getComponentMapping();

const form1 = require('./form1.json'); // form with wizard steps
const form2 = require('./form2.json'); // form without wizard steps (proudly assembled in Semantic Form Web Editor)

const getP = (queryParameterName, defaultValue) => {
return {
[queryParameterName]: getQueryParameter(queryParameterName, defaultValue)
};
return {
[queryParameterName]: getQueryParameter(queryParameterName, defaultValue)
};
};

const getQueryParameter = (parameterName, defaultValue) => {
const value = queryString.parse(window.location.search)[parameterName];
if (value) {
return value;
}
return defaultValue;
const value = queryString.parse(window.location.search)[parameterName];
if (value) {
return value;
}
return defaultValue;
};

class TestApp extends React.Component {
Expand All @@ -37,60 +38,60 @@ class TestApp extends React.Component {
this.refForm = React.createRef();
}

fetchTypeAheadValues = (query) => {
const possibleValues = require('./possibleValues.json');
return new Promise((resolve) => setTimeout(() => resolve(possibleValues), 1500));
};
fetchTypeAheadValues = (query) => {
const possibleValues = require('./possibleValues.json');
return new Promise((resolve) => setTimeout(() => resolve(possibleValues), 1500));
};

render() {
const modalProps = {
onHide: () => {
},
show: true,
title: 'Title'
};
render() {
const modalProps = {
onHide: () => {
},
show: true,
title: 'Title'
};

const options = {
i18n: {
'wizard.next': 'Next',
'wizard.previous': 'Previous',
'section.expand': 'Expand',
'section.collapse': 'Collapse'
},
intl: {
locale: 'cs'
},
modalView: false,
modalProps,
horizontalWizardNav: false,
wizardStepButtons: true,
enableForwardSkip: true,
...getP('startingQuestionId', 'layout-options-65'),
startingStep: 1
};
const options = {
i18n: {
'wizard.next': 'Next',
'wizard.previous': 'Previous',
'section.expand': 'Expand',
'section.collapse': 'Collapse'
},
intl: {
locale: 'cs'
},
modalView: false,
modalProps,
horizontalWizardNav: false,
wizardStepButtons: true,
enableForwardSkip: true,
...getP('startingQuestionId', 'layout-options-65'),
startingStep: 1
};

return (
<div className="p-4">
<SForms
ref={this.refForm}
form={this.state.selectedForm}
options={options}
fetchTypeAheadValues={this.fetchTypeAheadValues}
isFormValid={(isFormValid) => this.setState({isFormValid})}
componentMapRules={componentMapping}
/>
<button
disabled={!this.state.isFormValid}
style={{width: '100px', margin: '1rem -50px', position: 'relative', left: '50%'}}
onClick={() => {
this.setState((prevState) => ({selectedForm: prevState.selectedForm === form2 ? form1 : form2}));
}}
>
Switch form
</button>
</div>
);
}
return (
<div className="p-4">
<SForms
ref={this.refForm}
form={this.state.selectedForm}
options={options}
fetchTypeAheadValues={this.fetchTypeAheadValues}
isFormValid={(isFormValid) => this.setState({isFormValid})}
componentMapRules={componentMapping}
/>
<button
disabled={!this.state.isFormValid}
style={{width: '100px', margin: '1rem -50px', position: 'relative', left: '50%'}}
onClick={() => {
this.setState((prevState) => ({selectedForm: prevState.selectedForm === form2 ? form1 : form2}));
}}
>
Switch form
</button>
</div>
);
}
}

ReactDOM.render(<TestApp/>, document.getElementById('container'));

0 comments on commit 7eb8685

Please sign in to comment.