LT-253: Creating radio group component
This commit is contained in:
parent
cb875b1913
commit
9d31b49997
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
docs/
|
docs/
|
||||||
.meteor/local
|
.meteor/local
|
||||||
.meteor/meteorite
|
.meteor/meteorite
|
||||||
|
.meteor/dev_bundle
|
||||||
node_modules
|
node_modules
|
||||||
Packages/active-entry/helloworld/
|
Packages/active-entry/helloworld/
|
||||||
LesionTracker/tests/nightwatch/reports/
|
LesionTracker/tests/nightwatch/reports/
|
||||||
|
|||||||
@ -29,6 +29,11 @@ Package.onUse(function(api) {
|
|||||||
'styles/common/spacings.styl'
|
'styles/common/spacings.styl'
|
||||||
], 'client');
|
], 'client');
|
||||||
|
|
||||||
|
// Component styles
|
||||||
|
api.addFiles([
|
||||||
|
'styles/components/radio.styl'
|
||||||
|
], 'client');
|
||||||
|
|
||||||
// Rounded Button Group
|
// Rounded Button Group
|
||||||
api.addFiles([
|
api.addFiles([
|
||||||
'components/roundedButtonGroup/roundedButtonGroup.html',
|
'components/roundedButtonGroup/roundedButtonGroup.html',
|
||||||
|
|||||||
36
Packages/design/styles/components/radio.styl
Normal file
36
Packages/design/styles/components/radio.styl
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
@import "{design}/app"
|
||||||
|
|
||||||
|
.group-radio
|
||||||
|
label
|
||||||
|
cursor: pointer
|
||||||
|
input
|
||||||
|
height: 0
|
||||||
|
width: 0
|
||||||
|
span
|
||||||
|
padding-left: 23px
|
||||||
|
position: relative
|
||||||
|
&:before
|
||||||
|
background: white
|
||||||
|
border-radius: 8px
|
||||||
|
content: ''
|
||||||
|
display: block
|
||||||
|
height: 16px
|
||||||
|
left: 0
|
||||||
|
position: absolute
|
||||||
|
top: 50%
|
||||||
|
transform(translateY(-50%))
|
||||||
|
width: 16px
|
||||||
|
input:focus + span:before
|
||||||
|
// TODO: [design] define a outline for the design
|
||||||
|
outline: none
|
||||||
|
box-shadow: 0 0 2px 2px $textSecondaryColor
|
||||||
|
input:checked + span:after
|
||||||
|
background: $uiBorderColorDark
|
||||||
|
border-radius: 5px
|
||||||
|
content: ''
|
||||||
|
height: 10px
|
||||||
|
left: 3px
|
||||||
|
position: absolute
|
||||||
|
top: 50%
|
||||||
|
transform(translateY(-50%))
|
||||||
|
width: 10px
|
||||||
@ -1,70 +1,51 @@
|
|||||||
<template name="additionalFindings">
|
<template name="additionalFindings">
|
||||||
<div class="additionalFindings">
|
<div class="additionalFindings">
|
||||||
<div class="scrollArea">
|
<div class="scrollArea">
|
||||||
<div class="row">
|
{{#form schema=currentSchema}}
|
||||||
<div class="header">
|
<div class="row">
|
||||||
Additional Findings: Baseline
|
<div class="header">Additional Findings: Baseline</div>
|
||||||
|
{{>groupRadio labelClass='form-group' key='measurableDisease'}}
|
||||||
</div>
|
</div>
|
||||||
{{>radioOptionGroup (stateDataWithKey "measurableDisease")}}
|
<div class="row">
|
||||||
</div>
|
<div class="header">Supplementary Measurements</div>
|
||||||
|
{{>selectInput (stateDataWithKey "numberOfBoneLesions")}}
|
||||||
<!-- <h4>Testing dynamic components</h4>
|
{{>select2Input
|
||||||
{{#form id="testForm" schema=currentSchema}}
|
key="regionsOfMetastaticDisease"
|
||||||
{{>inputText key='test' label='testing'}}
|
select2Options=regionsOfMetastaticDiseaseSelect2Options
|
||||||
{{>groupRadio mixins='schemaData' key='acceptableImageQuality'}}
|
state=state
|
||||||
{{/form}} -->
|
currentSchema=currentSchema
|
||||||
|
}}
|
||||||
<div class="row">
|
{{>groupRadio labelClass='form-group' key='tracerRelatedToMetastaticDisease'}}
|
||||||
<div class="header">
|
|
||||||
Supplementary Measurements
|
|
||||||
</div>
|
</div>
|
||||||
{{>selectInput (stateDataWithKey "numberOfBoneLesions")}}
|
<div class="row">
|
||||||
{{>select2Input
|
<div class="header">Image Quality</div>
|
||||||
key="regionsOfMetastaticDisease"
|
{{>groupRadio labelClass='form-group' key='acceptableImageQuality'}}
|
||||||
select2Options=regionsOfMetastaticDiseaseSelect2Options
|
{{>groupRadio labelClass='form-group' key='adequateAnatomicalCoverage'}}
|
||||||
state=state
|
{{>groupRadio labelClass='form-group' key='presenceOfContrast'}}
|
||||||
currentSchema=currentSchema
|
|
||||||
}}
|
|
||||||
{{>radioOptionGroup (stateDataWithKey "tracerRelatedToMetastaticDisease")}}
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="header">
|
|
||||||
Image Quality
|
|
||||||
</div>
|
</div>
|
||||||
{{>radioOptionGroup (stateDataWithKey "acceptableImageQuality")}}
|
<div class="row">
|
||||||
{{>radioOptionGroup (stateDataWithKey "adequateAnatomicalCoverage")}}
|
<div class="header">Additional Screen Captures</div>
|
||||||
{{>radioOptionGroup (stateDataWithKey "presenceOfContrast")}}
|
<div class="entrySection buttonSection">
|
||||||
</div>
|
<div class="svgContainer">
|
||||||
<div class="row">
|
<svg>
|
||||||
<div class="header">
|
<use xlink:href="/packages/lesiontracker/assets/icons.svg#icon-create-screen-capture"></use>
|
||||||
Additional Screen Captures
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="entrySection buttonSection">
|
<div class="buttonLabel noselect">Add new screen capture</div>
|
||||||
<div class="svgContainer">
|
|
||||||
<svg>
|
|
||||||
<use xlink:href="/packages/lesiontracker/assets/icons.svg#icon-create-screen-capture"></use>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class="buttonLabel noselect">
|
|
||||||
Add new screen capture
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="row">
|
<div class="header">Comments</div>
|
||||||
<div class="header">
|
<div class="entrySection buttonSection">
|
||||||
Comments
|
<div class="svgContainer">
|
||||||
</div>
|
<svg>
|
||||||
<div class="entrySection buttonSection">
|
<use xlink:href="/packages/lesiontracker/assets/icons.svg#icon-create-comment"></use>
|
||||||
<div class="svgContainer">
|
</svg>
|
||||||
<svg>
|
</div>
|
||||||
<use xlink:href="/packages/lesiontracker/assets/icons.svg#icon-create-comment"></use>
|
<div class="buttonLabel noselect">Add a comment</div>
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class="buttonLabel noselect">
|
|
||||||
Add a comment
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/form}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -38,6 +38,13 @@
|
|||||||
&:not(:last-child)
|
&:not(:last-child)
|
||||||
border-bottom: $uiBorderThickness solid $uiBorderColorDark
|
border-bottom: $uiBorderThickness solid $uiBorderColorDark
|
||||||
|
|
||||||
|
& > .wrapperText
|
||||||
|
display: block
|
||||||
|
font-weight: bold
|
||||||
|
line-height: 15px
|
||||||
|
margin: 10px 0 8px
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
h5
|
h5
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
margin-bottom: 8px
|
margin-bottom: 8px
|
||||||
@ -48,10 +55,11 @@
|
|||||||
display: inline-block
|
display: inline-block
|
||||||
padding: 5px
|
padding: 5px
|
||||||
|
|
||||||
.radio-group
|
// TODO: remove radio-group
|
||||||
|
.radio-group, .group-radio
|
||||||
height: 30px
|
height: 30px
|
||||||
|
|
||||||
.radio-option
|
label
|
||||||
display: inline-block
|
display: inline-block
|
||||||
float: left
|
float: left
|
||||||
font-size: 14px
|
font-size: 14px
|
||||||
|
|||||||
@ -44,7 +44,7 @@ OHIF.mixins.form = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the component main and style elements
|
// Set the component main and style elements
|
||||||
component.$style = component.$element = instance.$('form').first();
|
component.$style = component.$element = instance.$('form:first');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { $ } from 'meteor/jquery';
|
|||||||
* It may be used to manage all components that belong to forms
|
* It may be used to manage all components that belong to forms
|
||||||
*/
|
*/
|
||||||
OHIF.mixins.formItem = new OHIF.Mixin({
|
OHIF.mixins.formItem = new OHIF.Mixin({
|
||||||
dependencies: 'component',
|
dependencies: 'schemaData',
|
||||||
composition: {
|
composition: {
|
||||||
|
|
||||||
onCreated() {
|
onCreated() {
|
||||||
@ -113,7 +113,7 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
|||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
// Set the element to be controlled
|
// Set the element to be controlled
|
||||||
component.$element = instance.$(':input:first');
|
component.$element = instance.$(':input').first();
|
||||||
|
|
||||||
// Set the element to be styled
|
// Set the element to be styled
|
||||||
component.$style = component.$element;
|
component.$style = component.$element;
|
||||||
|
|||||||
@ -45,6 +45,14 @@ OHIF.mixins.group = new OHIF.Mixin({
|
|||||||
component.registeredItems.forEach(child => child.readonly(isReadonly));
|
component.registeredItems.forEach(child => child.readonly(isReadonly));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
onRendered() {
|
||||||
|
const instance = Template.instance();
|
||||||
|
const component = instance.component;
|
||||||
|
|
||||||
|
// Set the element to be controlled
|
||||||
|
component.$element = instance.$('.component-group:first');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,8 +16,9 @@ OHIF.mixins.groupRadio = new OHIF.Mixin({
|
|||||||
// Get the selected radio's value or select a radio based on value
|
// Get the selected radio's value or select a radio based on value
|
||||||
component.value = value => {
|
component.value = value => {
|
||||||
const isGet = _.isUndefined(value);
|
const isGet = _.isUndefined(value);
|
||||||
const $elements = $();
|
const elements = [];
|
||||||
component.registeredItems.forEach(child => $elements.add(child.$element));
|
component.registeredItems.forEach(child => elements.push(child.$element[0]));
|
||||||
|
const $elements = $(elements);
|
||||||
if (isGet) {
|
if (isGet) {
|
||||||
return $elements.filter(':checked').val();
|
return $elements.filter(':checked').val();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,31 +3,39 @@ import { Blaze } from 'meteor/blaze';
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
|
|
||||||
|
// Helper function to get the component's current schema
|
||||||
|
const getCurrentSchema = (parentComponent, key) => {
|
||||||
|
// Get the parent component schema
|
||||||
|
const schema = parentComponent && parentComponent.schema;
|
||||||
|
|
||||||
|
// Stop here if there's no key or schema defined
|
||||||
|
if (!key || !schema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current schema data using component's key
|
||||||
|
const currentSchema = schema._schema[key];
|
||||||
|
|
||||||
|
// Return the component's schema definitions
|
||||||
|
return currentSchema;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* schemaData: change the component data based on its form's schema data
|
* schemaData: change the component data based on its form's schema data
|
||||||
*/
|
*/
|
||||||
OHIF.mixins.schemaData = new OHIF.Mixin({
|
OHIF.mixins.schemaData = new OHIF.Mixin({
|
||||||
dependencies: 'formItem',
|
dependencies: 'component',
|
||||||
composition: {
|
composition: {
|
||||||
|
|
||||||
onData() {
|
onData() {
|
||||||
|
// Get the current template data
|
||||||
const data = Template.currentData();
|
const data = Template.currentData();
|
||||||
|
|
||||||
|
// Get the parent component
|
||||||
const parent = OHIF.blaze.getParentComponent(Blaze.currentView);
|
const parent = OHIF.blaze.getParentComponent(Blaze.currentView);
|
||||||
|
|
||||||
// Get the parent component schema
|
|
||||||
const schema = parent && parent.schema;
|
|
||||||
|
|
||||||
// Get the current component's key
|
|
||||||
const key = data.key;
|
|
||||||
|
|
||||||
// Stop here if there's no key or schema defined
|
|
||||||
if (!key || !schema) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current schema data using component's key
|
// Get the current schema data using component's key
|
||||||
const currentSchema = schema._schema[key];
|
const currentSchema = getCurrentSchema(parent, data.key);
|
||||||
|
|
||||||
// Stop here if there's no schema data for current key
|
// Stop here if there's no schema data for current key
|
||||||
if (!currentSchema) {
|
if (!currentSchema) {
|
||||||
@ -39,7 +47,42 @@ OHIF.mixins.schemaData = new OHIF.Mixin({
|
|||||||
data.label = new ReactiveVar(currentSchema.label);
|
data.label = new ReactiveVar(currentSchema.label);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [design] convert allowedValues to items and find a way to get key/value pairs
|
// Fill the items if it's an array schema
|
||||||
|
if (!data.items && Array.isArray(currentSchema.allowedValues)) {
|
||||||
|
// Initialize the items array
|
||||||
|
data.items = [];
|
||||||
|
|
||||||
|
// Get the values and labels arrays from schema
|
||||||
|
const values = currentSchema.allowedValues;
|
||||||
|
const labels = currentSchema.valuesLabels || [];
|
||||||
|
|
||||||
|
// Iterate the allowed values array
|
||||||
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
// Push the current item to the items array
|
||||||
|
data.items.push({
|
||||||
|
value: values[i],
|
||||||
|
label: labels[i] || values[i]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onMixins() {
|
||||||
|
const instance = Template.instance();
|
||||||
|
const component = instance.component;
|
||||||
|
|
||||||
|
// Get the current schema data using component's key
|
||||||
|
const currentSchema = getCurrentSchema(component.parent, instance.data.key);
|
||||||
|
|
||||||
|
// Stop here if there's no schema data for current key
|
||||||
|
if (!currentSchema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the component with its default value after rendering
|
||||||
|
if (currentSchema.defaultValue) {
|
||||||
|
component.value(currentSchema.defaultValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,7 +77,7 @@ Template.baseComponent.constructView = function(contentFunc, elseFunc) {
|
|||||||
|
|
||||||
// Throw an error if the wrapper template does not exists
|
// Throw an error if the wrapper template does not exists
|
||||||
if (!wrapperTemplate) {
|
if (!wrapperTemplate) {
|
||||||
throw new Error(`Template ${data.base} not found.`);
|
throw new Error(`Template ${wrapper} not found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone the wrapper template to avoid assigning duplicated handlers
|
// Clone the wrapper template to avoid assigning duplicated handlers
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
{{#if this.labelAfter}}
|
{{#if this.labelAfter}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<span class="wrapperLabelText">{{reactive this.label}}</span>
|
<span class="wrapperText">{{reactive this.label}}</span>
|
||||||
{{#unless this.labelAfter}}
|
{{#unless this.labelAfter}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
{{#if this.labelAfter}}
|
{{#if this.labelAfter}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<span class="wrapperTitleText">{{reactive this.label}}</span>
|
<span class="wrapperText">{{reactive this.label}}</span>
|
||||||
{{#unless this.labelAfter}}
|
{{#unless this.labelAfter}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template name="group">
|
<template name="group">
|
||||||
{{#baseComponent (extend this
|
{{#baseComponent (extend this
|
||||||
|
class=(concat 'component-group ' this.class)
|
||||||
base="baseDiv"
|
base="baseDiv"
|
||||||
mixins=(concat "group " this.mixins)
|
mixins=(concat "group " this.mixins)
|
||||||
)}}
|
)}}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
<template name="groupRadio">
|
<template name="groupRadio">
|
||||||
{{#group (extend this
|
{{#group (extend this
|
||||||
class=(concat 'form-group ' this.class)
|
class=(concat 'group-radio ' this.class)
|
||||||
|
mixins=(concat "groupRadio " this.mixins)
|
||||||
wrappers=(concat ''
|
wrappers=(concat ''
|
||||||
this.wrappers
|
|
||||||
(valueIf reactive this.label 'wrapperTitle ' '')
|
(valueIf reactive this.label 'wrapperTitle ' '')
|
||||||
|
this.wrappers
|
||||||
)
|
)
|
||||||
)}}
|
)}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
<template name="inputRadio">
|
<template name="inputRadio">
|
||||||
{{#baseComponent (extend this
|
{{#baseComponent (extend this
|
||||||
base='baseInput'
|
base='baseInput'
|
||||||
|
type='radio'
|
||||||
mixins=(concat 'input ' this.mixins)
|
mixins=(concat 'input ' this.mixins)
|
||||||
labelAfter=(valueIf (isDefined this.labelAfter) this.labelAfter true)
|
labelAfter=(valueIf (isDefined this.labelAfter) this.labelAfter true)
|
||||||
labelClass=(concat 'checkboxLabel' this.labelClass)
|
labelClass=(concat 'checkboxLabel' this.labelClass)
|
||||||
wrappers=(concat ''
|
wrappers=(concat ''
|
||||||
this.wrappers
|
|
||||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||||
|
this.wrappers
|
||||||
)
|
)
|
||||||
)}}
|
)}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
class=(concat 'form-control ' this.class)
|
class=(concat 'form-control ' this.class)
|
||||||
mixins=(concat 'select ' this.mixins)
|
mixins=(concat 'select ' this.mixins)
|
||||||
wrappers=(concat ''
|
wrappers=(concat ''
|
||||||
this.wrappers
|
|
||||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||||
|
this.wrappers
|
||||||
)
|
)
|
||||||
)}}
|
)}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
|
|||||||
@ -4,8 +4,8 @@
|
|||||||
class=(concat 'form-control ' this.class)
|
class=(concat 'form-control ' this.class)
|
||||||
mixins=(concat 'input ' this.mixins)
|
mixins=(concat 'input ' this.mixins)
|
||||||
wrappers=(concat ''
|
wrappers=(concat ''
|
||||||
this.wrappers
|
|
||||||
(valueIf reactive this.label 'wrapperLabel ' '')
|
(valueIf reactive this.label 'wrapperLabel ' '')
|
||||||
|
this.wrappers
|
||||||
)
|
)
|
||||||
)}}
|
)}}
|
||||||
{{>UI.contentBlock}}
|
{{>UI.contentBlock}}
|
||||||
|
|||||||
@ -62,7 +62,13 @@ Template.registerHelper('or', (...values) => {
|
|||||||
// Choose the first truthy value in the given values
|
// Choose the first truthy value in the given values
|
||||||
Template.registerHelper('choose', (...values) => {
|
Template.registerHelper('choose', (...values) => {
|
||||||
let result;
|
let result;
|
||||||
_.each(_.initial(values, 1), value => value && (result = value));
|
_.each(_.initial(values, 1), value => {
|
||||||
|
if (result) {
|
||||||
|
return;
|
||||||
|
} else if (value) {
|
||||||
|
result = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user