LT-67: Styling select2 error state and adding its error tooltip
This commit is contained in:
1 parent
620f5fd4ff
commit
c05e36eca8
9 files changed
+106
-36
No files matched your search
@@ -27,6 +27,18 @@ OHIF.mixins.form = new OHIF.Mixin({
|
||||
// Enable reactivity by changing a Tracker.Dependency observer
|
||||
component.validationObserver.changed();
|
||||
}, 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() {
|
||||
@@ -35,16 +47,6 @@ OHIF.mixins.form = new OHIF.Mixin({
|
||||
|
||||
// Set the component main and style elements
|
||||
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: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { OHIF } from 'meteor/ohif:core';
|
||||
import { Template } from 'meteor/templating';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import { $ } from 'meteor/jquery';
|
||||
|
||||
@@ -53,6 +54,19 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
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
|
||||
component.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) => {
|
||||
if (isShow) {
|
||||
console.warn('>>>>message', message);
|
||||
if (isShow && message) {
|
||||
// Stop here if the tooltip is already created
|
||||
if (component.$wrapper.next('.tooltip').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the tooltip
|
||||
component.$wrapper.tooltip({
|
||||
trigger: 'manual',
|
||||
title: message
|
||||
}).tooltip('show');
|
||||
} else {
|
||||
// Destroy the tooltip
|
||||
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
|
||||
component.getForm = () => {
|
||||
let currentComponent = component;
|
||||
@@ -198,25 +243,31 @@ OHIF.mixins.formItem = new OHIF.Mixin({
|
||||
focus(event, instance) {
|
||||
const component = instance.component;
|
||||
|
||||
// Stop here if it is an group
|
||||
if (component.isGroup || component.isCustomFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent event bubbling
|
||||
event.stopPropagation();
|
||||
|
||||
// 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);
|
||||
}
|
||||
// Check for state messages and show it
|
||||
component.toggleMessage(true);
|
||||
},
|
||||
|
||||
blur(event, instance) {
|
||||
const component = instance.component;
|
||||
|
||||
// Stop here if it is an group
|
||||
if (component.isGroup || component.isCustomFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent event bubbling
|
||||
event.stopPropagation();
|
||||
|
||||
// Hide any tooltips
|
||||
component.toggleTooltip(false);
|
||||
// Hide state messages
|
||||
component.toggleMessage(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ OHIF.mixins.group = new OHIF.Mixin({
|
||||
const instance = Template.instance();
|
||||
const component = instance.component;
|
||||
|
||||
// Set the group identifier flag
|
||||
component.isGroup = true;
|
||||
|
||||
// Run this computation every time the schema property is changed
|
||||
instance.autorun(() => {
|
||||
let schema = instance.data.schema;
|
||||
|
||||
@@ -11,6 +11,9 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
onCreated() {
|
||||
const instance = Template.instance();
|
||||
|
||||
// Set the custom focus flag
|
||||
instance.component.isCustomFocus = true;
|
||||
|
||||
// Check if this select will include a placeholder
|
||||
const placeholder = instance.data.options && instance.data.options.placeholder;
|
||||
if (placeholder) {
|
||||
@@ -54,6 +57,22 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
|
||||
// Store the select2 instance to allow its further destruction
|
||||
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() {
|
||||
@@ -62,16 +81,6 @@ OHIF.mixins.select2 = new OHIF.Mixin({
|
||||
|
||||
// Destroy the select2 instance to remove unwanted DOM elements
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user