From c05e36eca8cc180f2c7c4889b39175b6e306b107 Mon Sep 17 00:00:00 2001 From: Bruno Alves de Faria Date: Thu, 1 Sep 2016 13:33:17 -0300 Subject: [PATCH] LT-67: Styling select2 error state and adding its error tooltip --- Packages/design/styles/components/states.styl | 5 ++ .../additionalFindings.html | 2 +- .../serverInformationDicomWeb.html | 2 +- .../serverInformationForm.html | 2 +- .../client/components/base/mixins/form.js | 22 +++--- .../client/components/base/mixins/formItem.js | 73 ++++++++++++++++--- .../client/components/base/mixins/group.js | 3 + .../client/components/base/mixins/select2.js | 29 +++++--- Packages/worklist/both/schema.js | 4 +- 9 files changed, 106 insertions(+), 36 deletions(-) diff --git a/Packages/design/styles/components/states.styl b/Packages/design/styles/components/states.styl index e8fa37fa5..1915cdea8 100644 --- a/Packages/design/styles/components/states.styl +++ b/Packages/design/styles/components/states.styl @@ -22,3 +22,8 @@ theme('background-color', '$uiStateError') theme('border-color', '$uiStateErrorBorder') theme('color', '$uiStateErrorText') + + .select2-selection + theme('background-color', '$uiStateError') + theme('border-color', '$uiStateErrorBorder') + theme('color', '$uiStateErrorText') diff --git a/Packages/lesiontracker/client/components/additionalFindings/additionalFindings.html b/Packages/lesiontracker/client/components/additionalFindings/additionalFindings.html index 6c50cc4de..dcd49b839 100644 --- a/Packages/lesiontracker/client/components/additionalFindings/additionalFindings.html +++ b/Packages/lesiontracker/client/components/additionalFindings/additionalFindings.html @@ -15,7 +15,7 @@ key='regionsOfMetastaticDisease' multiple=true options=(clone - placeholder='Choose a region...' + placeholder='Choose a region' allowClear=true ) }} diff --git a/Packages/lesiontracker/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html b/Packages/lesiontracker/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html index 49db1b73c..8a2dc16be 100644 --- a/Packages/lesiontracker/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html +++ b/Packages/lesiontracker/client/components/serverInformation/serverInformationDicomWeb/serverInformationDicomWeb.html @@ -11,7 +11,7 @@
{{>inputSelect labelClass='form-group' key='imageRendering' hideSearch=true - options=(clone placeholder='Select an option...')}} + options=(clone placeholder='Select an option')}}
{{>inputText labelClass='form-group' key='qidoRoot'}} diff --git a/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.html b/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.html index 9101be616..132a6b5da 100644 --- a/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.html +++ b/Packages/lesiontracker/client/components/serverInformation/serverInformationForm/serverInformationForm.html @@ -8,7 +8,7 @@
{{>inputSelect labelClass='form-group' key='type' hideSearch=true disabled=(eq this.mode.get 'edit') - options=(clone placeholder='Choose a server type...')}} + options=(clone placeholder='Choose a server type')}}

diff --git a/Packages/ohif-core/client/components/base/mixins/form.js b/Packages/ohif-core/client/components/base/mixins/form.js index 9a6db08a6..ab9bfbeb0 100644 --- a/Packages/ohif-core/client/components/base/mixins/form.js +++ b/Packages/ohif-core/client/components/base/mixins/form.js @@ -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: { diff --git a/Packages/ohif-core/client/components/base/mixins/formItem.js b/Packages/ohif-core/client/components/base/mixins/formItem.js index 2842e1dab..88b7c4ae8 100644 --- a/Packages/ohif-core/client/components/base/mixins/formItem.js +++ b/Packages/ohif-core/client/components/base/mixins/formItem.js @@ -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); } } diff --git a/Packages/ohif-core/client/components/base/mixins/group.js b/Packages/ohif-core/client/components/base/mixins/group.js index 3c5356831..c2e87a981 100644 --- a/Packages/ohif-core/client/components/base/mixins/group.js +++ b/Packages/ohif-core/client/components/base/mixins/group.js @@ -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; diff --git a/Packages/ohif-core/client/components/base/mixins/select2.js b/Packages/ohif-core/client/components/base/mixins/select2.js index 68453b389..987495dd1 100644 --- a/Packages/ohif-core/client/components/base/mixins/select2.js +++ b/Packages/ohif-core/client/components/base/mixins/select2.js @@ -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(); - } } } }); diff --git a/Packages/worklist/both/schema.js b/Packages/worklist/both/schema.js index 1ce640523..4eec4cc74 100644 --- a/Packages/worklist/both/schema.js +++ b/Packages/worklist/both/schema.js @@ -59,8 +59,8 @@ export const DICOMWebServer = new SimpleSchema({ imageRendering: { type: String, label: 'Image rendering', - allowedValues: ['wadouri', 'orthanc'], - valuesLabels: ['WADO URI', 'ORTHANC'] + allowedValues: ['', 'wadouri', 'orthanc'], + valuesLabels: ['', 'WADO URI', 'ORTHANC'] }, qidoRoot: { type: String,