diff --git a/css/backoffice/utils/helpers/_text-decoration.scss b/css/backoffice/utils/helpers/_text-decoration.scss index c45dc8600..cdef6ef5e 100644 --- a/css/backoffice/utils/helpers/_text-decoration.scss +++ b/css/backoffice/utils/helpers/_text-decoration.scss @@ -38,6 +38,10 @@ $ibo-is-code--padding: 1.25rem 1.5rem !default; cursor: help; } +.ibo-is-disabled { + cursor: not-allowed !important; /* Note: !important is necessary as it needs to overload any standard rules */ +} + /* Class to display a hint on elements that have a tooltip for further description */ .ibo-has-description { &::after { diff --git a/js/layouts/tab-container/regular-tabs.js b/js/layouts/tab-container/regular-tabs.js index fc2b509bc..bafbf85e8 100644 --- a/js/layouts/tab-container/regular-tabs.js +++ b/js/layouts/tab-container/regular-tabs.js @@ -124,5 +124,16 @@ $.widget( "itop.regulartabs", $.ui.tabs, { this._off( prevPanels.not( this.panels ) ); } }, - -}); \ No newline at end of file + // JQuery UI overload + disable: function(index){ + const panel = this._getPanelForTab( index ); + panel.addClass('ibo-is-hidden'); // Do not use .hide() since it alters the tab state + this._super( index ); + }, + // JQuery UI overload + enable: function(index) { + const panel = this._getPanelForTab( index ); + panel.removeClass('ibo-is-hidden'); // Do not use .show() since it alters the tab state + this._super( index ); + }, +}); diff --git a/js/layouts/tab-container/scrollable-tabs.js b/js/layouts/tab-container/scrollable-tabs.js index 3b9c1d2e1..9a088db09 100644 --- a/js/layouts/tab-container/scrollable-tabs.js +++ b/js/layouts/tab-container/scrollable-tabs.js @@ -377,4 +377,16 @@ $.widget( "itop.scrollabletabs", $.ui.tabs, { setTab : function(tab){ this.active = tab; }, -}); \ No newline at end of file + // JQuery UI overload + disable: function(index){ + const panel = this._getPanelForTab( this.tabs[index] ); + panel.addClass('ibo-is-hidden'); // Do not use .hide() since it alters the tab state + this._super( index ); + }, + // JQuery UI overload + enable: function(index) { + const panel = this._getPanelForTab( this.tabs[index] ); + panel.removeClass('ibo-is-hidden'); // Do not use .show() since it alters the tab state + this._super( index ); + }, +}); diff --git a/js/layouts/tab-container/tab-container.js b/js/layouts/tab-container/tab-container.js index 263d9dd48..985127f00 100644 --- a/js/layouts/tab-container/tab-container.js +++ b/js/layouts/tab-container/tab-container.js @@ -15,6 +15,7 @@ $(function() css_classes: { is_hidden: 'ibo-is-hidden', + is_disabled: 'ibo-is-disabled', is_transparent: 'ibo-is-transparent', is_opaque: 'ibo-is-opaque', is_scrollable: 'ibo-is-scrollable', @@ -252,6 +253,11 @@ $(function() // Prevent anchor default behaviour oEvent.preventDefault(); + if (oExtraTabTogglerElem.attr('aria-disabled') === 'true') { + // Corresponding tab is disabled, do nothing + oEvent.stopPropagation(); + return; + } // Trigger click event on real tab toggler (the hidden one) const sTargetTabId = oExtraTabTogglerElem.attr('href').replace(/#/, ''); this.element.find(this.js_selectors.tab_header+'[data-tab-id="'+sTargetTabId+'"] '+this.js_selectors.tab_toggler).trigger('click'); @@ -297,17 +303,30 @@ $(function() const sTabId = oTabHeaderElem.attr('data-tab-id'); const oMatchingExtraTabElem = this.element.find(this.js_selectors.extra_tab_toggler+'[href="#'+sTabId+'"]'); + // Disabled tabs should be disabled in the ExtraTabs list as well + let bIsDisabled = false; + if (oTabHeaderElem.attr('aria-disabled') === 'true') { + bIsDisabled = true; + } // Manually check if the tab header is visible if the info isn't passed if (bIsVisible === null) { - bIsVisible = CombodoGlobalToolbox.IsElementVisibleToTheUser(oTabHeaderElem[0], true, 2); - } + bIsVisible = CombodoGlobalToolbox.IsElementVisibleToTheUser(oTabHeaderElem[0], true, 2); + } // Hide/show the corresponding extra tab element - if (bIsVisible) { - oMatchingExtraTabElem.addClass(this.css_classes.is_hidden); - } else { - oMatchingExtraTabElem.removeClass(this.css_classes.is_hidden); - } + if (bIsVisible) { + oMatchingExtraTabElem.addClass(this.css_classes.is_hidden); + } else { + oMatchingExtraTabElem.removeClass(this.css_classes.is_hidden); + } + // Enable/disable the corresponding extra tab element + if (bIsDisabled) { + oMatchingExtraTabElem.attr('aria-disabled', 'true'); + oMatchingExtraTabElem.addClass(this.css_classes.is_disabled); + } else { + oMatchingExtraTabElem.attr('aria-disabled', 'false'); + oMatchingExtraTabElem.removeClass(this.css_classes.is_disabled); + } }, // - Update extra tabs list _updateExtraTabsList: function () { @@ -326,7 +345,7 @@ $(function() * @return {string} The [data-tab-id] of the iIdx-th tab (zero based). Can return undefined if it has not [data-tab-id] attribute * @private */ - _getTabIdFromTabIndex(iIdx) { + _getTabIdFromTabIndex: function(iIdx) { return this.element.children(this.js_selectors.tabs_list).children(this.js_selectors.tab_header).eq(iIdx).attr('data-tab-id'); }, /** @@ -334,10 +353,41 @@ $(function() * @return {number} The index (zero based) of the tab. If no matching tab, 0 will be returned. * @private */ - _getTabIndexFromTabId(sId) { + _getTabIndexFromTabId: function(sId) { const oTabElem = this.element.children(this.js_selectors.tabs_list).children(this.js_selectors.tab_header+'[data-tab-id="'+sId+'"]'); return oTabElem.length === 0 ? 0 : oTabElem.prevAll().length; - } + }, + /** + * @param sId {string} The [data-tab-id] of the tab + * @return {Object} The jQuery object representing the tab element + * + * @private + */ + _getTabElementFromTabId: function(sId) { + return this.element.children(this.js_selectors.tabs_list).children(this.js_selectors.tab_header+'[data-tab-id="'+sId+'"]'); + }, + /** + * @param sId {string} The [data-tab-id] of the tab + * @return {Object} The jQuery object representing the tab element + */ + disableTab: function(sId){ + const tabsWidget = this.GetTabsWidget(); + const iIdx = this._getTabIndexFromTabId(sId); + tabsWidget.disable(iIdx); + const tabElement = this._getTabElementFromTabId(sId); + this._updateTabHeaderDisplay(tabElement); + }, + /** + * @param sId {string} The [data-tab-id] of the tab + * @return {Object} The jQuery object representing the tab element + */ + enableTab: function(sId){ + const tabsWidget = this.GetTabsWidget(); + const iIdx = this._getTabIndexFromTabId(sId); + tabsWidget.enable(iIdx); + const tabElement = this._getTabElementFromTabId(sId); + this._updateTabHeaderDisplay(tabElement); + } }); });