LT-67: Styling select2 error state and adding its error tooltip
This commit is contained in:
parent
620f5fd4ff
commit
c05e36eca8
@ -22,3 +22,8 @@
|
|||||||
theme('background-color', '$uiStateError')
|
theme('background-color', '$uiStateError')
|
||||||
theme('border-color', '$uiStateErrorBorder')
|
theme('border-color', '$uiStateErrorBorder')
|
||||||
theme('color', '$uiStateErrorText')
|
theme('color', '$uiStateErrorText')
|
||||||
|
|
||||||
|
.select2-selection
|
||||||
|
theme('background-color', '$uiStateError')
|
||||||
|
theme('border-color', '$uiStateErrorBorder')
|
||||||
|
theme('color', '$uiStateErrorText')
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
key='regionsOfMetastaticDisease'
|
key='regionsOfMetastaticDisease'
|
||||||
multiple=true
|
multiple=true
|
||||||
options=(clone
|
options=(clone
|
||||||
placeholder='Choose a region...'
|
placeholder='Choose a region'
|
||||||
allowClear=true
|
allowClear=true
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
{{>inputSelect labelClass='form-group' key='imageRendering' hideSearch=true
|
{{>inputSelect labelClass='form-group' key='imageRendering' hideSearch=true
|
||||||
options=(clone placeholder='Select an option...')}}
|
options=(clone placeholder='Select an option')}}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
{{>inputText labelClass='form-group' key='qidoRoot'}}
|
{{>inputText labelClass='form-group' key='qidoRoot'}}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
{{>inputSelect labelClass='form-group' key='type'
|
{{>inputSelect labelClass='form-group' key='type'
|
||||||
hideSearch=true disabled=(eq this.mode.get 'edit')
|
hideSearch=true disabled=(eq this.mode.get 'edit')
|
||||||
options=(clone placeholder='Choose a server type...')}}
|
options=(clone placeholder='Choose a server type')}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
|||||||
@ -27,6 +27,18 @@ OHIF.mixins.form = new OHIF.Mixin({
|
|||||||
// Enable reactivity by changing a Tracker.Dependency observer
|
// Enable reactivity by changing a Tracker.Dependency observer
|
||||||
component.validationObserver.changed();
|
component.validationObserver.changed();
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
|
// Change the validation function to focus the fields with error
|
||||||
|
const validateSelf = component.validate;
|
||||||
|
component.validate = () => {
|
||||||
|
// Call the original validation function
|
||||||
|
validateSelf();
|
||||||
|
|
||||||
|
// Focus the first error field if some validation failed
|
||||||
|
if (component.schema && component.schema._invalidKeys.length) {
|
||||||
|
instance.$('.state-error :input:first').focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
onRendered() {
|
onRendered() {
|
||||||
@ -35,16 +47,6 @@ OHIF.mixins.form = new OHIF.Mixin({
|
|||||||
|
|
||||||
// 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');
|
||||||
|
|
||||||
instance.autorun(() => {
|
|
||||||
// Run this computation everytime the validation is triggered
|
|
||||||
component.validationObserver.depend();
|
|
||||||
|
|
||||||
// Focus the first error field if some validation failed
|
|
||||||
if (component.schema && component.schema._invalidKeys.length) {
|
|
||||||
instance.$('.state-error :input:first').focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import { Tracker } from 'meteor/tracker';
|
import { Tracker } from 'meteor/tracker';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
import { _ } from 'meteor/underscore';
|
import { _ } from 'meteor/underscore';
|
||||||
import { $ } from 'meteor/jquery';
|
import { $ } from 'meteor/jquery';
|
||||||
|
|
||||||
@ -53,6 +54,19 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
|||||||
component.$wrapper[method]();
|
component.$wrapper[method]();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if the focus is inside this element
|
||||||
|
component.hasFocus = () => {
|
||||||
|
// Get the focused element
|
||||||
|
const focused = $(':focus')[0];
|
||||||
|
|
||||||
|
// Check if the focused element is inside the component
|
||||||
|
const contains = $.contains(component.$wrapper[0], focused);
|
||||||
|
const isEqual = component.$wrapper[0] === focused;
|
||||||
|
|
||||||
|
// Return true if he component has the focus
|
||||||
|
return contains || isEqual;
|
||||||
|
};
|
||||||
|
|
||||||
// Add or remove a state from the component
|
// Add or remove a state from the component
|
||||||
component.state = (state, flag) => {
|
component.state = (state, flag) => {
|
||||||
component.$wrapper.toggleClass(`state-${state}`, !!flag);
|
component.$wrapper.toggleClass(`state-${state}`, !!flag);
|
||||||
@ -71,19 +85,50 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Toggle the state over the component
|
// Toggle the tooltip over the component
|
||||||
component.toggleTooltip = (isShow, message) => {
|
component.toggleTooltip = (isShow, message) => {
|
||||||
if (isShow) {
|
if (isShow && message) {
|
||||||
console.warn('>>>>message', message);
|
// Stop here if the tooltip is already created
|
||||||
|
if (component.$wrapper.next('.tooltip').length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the tooltip
|
||||||
component.$wrapper.tooltip({
|
component.$wrapper.tooltip({
|
||||||
trigger: 'manual',
|
trigger: 'manual',
|
||||||
title: message
|
title: message
|
||||||
}).tooltip('show');
|
}).tooltip('show');
|
||||||
} else {
|
} else {
|
||||||
|
// Destroy the tooltip
|
||||||
component.$wrapper.tooltip('destroy');
|
component.$wrapper.tooltip('destroy');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Toggle a state message as a tooltip over the component
|
||||||
|
component.toggleMessage = isShow => {
|
||||||
|
// Check if the action is to hide
|
||||||
|
if (!isShow) {
|
||||||
|
Meteor.setTimeout(() => {
|
||||||
|
// Check if the component has the focus
|
||||||
|
if (component.hasFocus()) {
|
||||||
|
// Prevent the tooltip from being hidden
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide the tooltip
|
||||||
|
component.toggleTooltip(false);
|
||||||
|
}, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for error state and message
|
||||||
|
const errorMessage = component.$wrapper.attr('data-error');
|
||||||
|
if (errorMessage) {
|
||||||
|
// Show the tooltip with the error message
|
||||||
|
component.toggleTooltip(true, errorMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Search for the parent form component
|
// Search for the parent form component
|
||||||
component.getForm = () => {
|
component.getForm = () => {
|
||||||
let currentComponent = component;
|
let currentComponent = component;
|
||||||
@ -198,25 +243,31 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
|||||||
focus(event, instance) {
|
focus(event, instance) {
|
||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
|
// Stop here if it is an group
|
||||||
|
if (component.isGroup || component.isCustomFocus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent event bubbling
|
// Prevent event bubbling
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
// Check for error state and message
|
// Check for state messages and show it
|
||||||
const errorMessage = component.$wrapper.attr('data-error');
|
component.toggleMessage(true);
|
||||||
if (errorMessage) {
|
|
||||||
// Show the tooltip with the error message
|
|
||||||
component.toggleTooltip(true, errorMessage);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
blur(event, instance) {
|
blur(event, instance) {
|
||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
|
// Stop here if it is an group
|
||||||
|
if (component.isGroup || component.isCustomFocus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent event bubbling
|
// Prevent event bubbling
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
// Hide any tooltips
|
// Hide state messages
|
||||||
component.toggleTooltip(false);
|
component.toggleMessage(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,9 @@ OHIF.mixins.group = new OHIF.Mixin({
|
|||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
const component = instance.component;
|
const component = instance.component;
|
||||||
|
|
||||||
|
// Set the group identifier flag
|
||||||
|
component.isGroup = true;
|
||||||
|
|
||||||
// Run this computation every time the schema property is changed
|
// Run this computation every time the schema property is changed
|
||||||
instance.autorun(() => {
|
instance.autorun(() => {
|
||||||
let schema = instance.data.schema;
|
let schema = instance.data.schema;
|
||||||
|
|||||||
@ -11,6 +11,9 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
|||||||
onCreated() {
|
onCreated() {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
|
|
||||||
|
// Set the custom focus flag
|
||||||
|
instance.component.isCustomFocus = true;
|
||||||
|
|
||||||
// Check if this select will include a placeholder
|
// Check if this select will include a placeholder
|
||||||
const placeholder = instance.data.options && instance.data.options.placeholder;
|
const placeholder = instance.data.options && instance.data.options.placeholder;
|
||||||
if (placeholder) {
|
if (placeholder) {
|
||||||
@ -54,6 +57,22 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
|||||||
|
|
||||||
// Store the select2 instance to allow its further destruction
|
// Store the select2 instance to allow its further destruction
|
||||||
component.select2Instance = component.$element.data('select2');
|
component.select2Instance = component.$element.data('select2');
|
||||||
|
|
||||||
|
// Get the focusable elements
|
||||||
|
const elements = [];
|
||||||
|
elements.push(component.$element[0]);
|
||||||
|
elements.push(component.$element.nextAll('.select2:first').find('.select2-selection')[0]);
|
||||||
|
|
||||||
|
// Attach focus and blur handlers to focusable elements
|
||||||
|
$(elements).on('focus', event => {
|
||||||
|
event.stopPropagation();
|
||||||
|
// Show the state message on elements focus
|
||||||
|
component.toggleMessage(true);
|
||||||
|
}).on('blur', event => {
|
||||||
|
event.stopPropagation();
|
||||||
|
// Hide the state message on elements blur
|
||||||
|
component.toggleMessage(false);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onDestroyed() {
|
onDestroyed() {
|
||||||
@ -62,16 +81,6 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
|||||||
|
|
||||||
// Destroy the select2 instance to remove unwanted DOM elements
|
// Destroy the select2 instance to remove unwanted DOM elements
|
||||||
component.select2Instance.destroy();
|
component.select2Instance.destroy();
|
||||||
},
|
|
||||||
|
|
||||||
events: {
|
|
||||||
'focusin .select2-hidden-accessible'(event, instance) {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
// Redirect the focus to select2 focus control in case of hidden
|
|
||||||
// accessible being focused (e.g. clicking on outer label)
|
|
||||||
$(event.currentTarget).nextAll('.select2:first').find('.select2-selection').focus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -59,8 +59,8 @@ export const DICOMWebServer = new SimpleSchema({
|
|||||||
imageRendering: {
|
imageRendering: {
|
||||||
type: String,
|
type: String,
|
||||||
label: 'Image rendering',
|
label: 'Image rendering',
|
||||||
allowedValues: ['wadouri', 'orthanc'],
|
allowedValues: ['', 'wadouri', 'orthanc'],
|
||||||
valuesLabels: ['WADO URI', 'ORTHANC']
|
valuesLabels: ['', 'WADO URI', 'ORTHANC']
|
||||||
},
|
},
|
||||||
qidoRoot: {
|
qidoRoot: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user