diff --git a/public/javascripts/gantt.js b/public/javascripts/gantt.js index 232110b221..d9ed201896 100644 --- a/public/javascripts/gantt.js +++ b/public/javascripts/gantt.js @@ -233,23 +233,33 @@ function resizableSubjectColumn(){ ganttEntryClick = function(e){ var icon_expander = e.target; var subject = $(icon_expander.parentElement); - var subject_left = parseInt(subject.css('left')) + parseInt(icon_expander.offsetWidth); + const expander_width = parseInt(icon_expander.offsetWidth); + var subject_left = parseInt(subject.css('left')) + expander_width; var target_shown = null; var target_top = 0; var total_height = 0; var out_of_hierarchy = false; var iconChange = null; + let collapsed_parent_left = null; + let parent_is_collapsed = null; + const force_collapse_expand = e.ctrlKey; + function is_expander(el) { + return $(el).find('.expander').length > 0; + } if(subject.hasClass('open')) iconChange = function(element){ $(element).find('.expander').switchClass('icon-expanded', 'icon-collapsed'); $(element).removeClass('open'); + if (is_expander(element) && (element === subject || force_collapse_expand)) element.addClass('collapsed'); }; else iconChange = function(element){ $(element).find('.expander').switchClass('icon-collapsed', 'icon-expanded'); $(element).addClass('open'); + if (is_expander(element) && (element === subject || force_collapse_expand)) element.removeClass('collapsed'); }; iconChange(subject); + parent_is_collapsed = subject.hasClass('collapsed'); subject.nextAll('div').each(function(_, element){ var el = $(element); var json = el.data('collapse-expand'); @@ -268,31 +278,59 @@ ganttEntryClick = function(e){ return true; } - var is_shown = el.is(':visible'); - if(target_shown == null){ - target_shown = is_shown; - target_top = parseInt(el.css('top')); - total_height = 0; - } - if(is_shown == target_shown){ - $(el_task_bars).each(function(_, task) { - var el_task = $(task); + const is_target_to_update = (() => { + const target_left = parseInt(el.css('left')); + if (!subject.hasClass('open') || force_collapse_expand) { + return true; + } else { + if (is_expander(el)) { + if (collapsed_parent_left == null || collapsed_parent_left >= target_left + expander_width) { + // First element or the same level or higher as the most recent collapsed parent element + parent_is_collapsed = el.hasClass('collapsed'); + if (parent_is_collapsed) collapsed_parent_left = target_left + expander_width; + else collapsed_parent_left = null; + return true; + } + } else if (parent_is_collapsed && collapsed_parent_left >= target_left) { + // Elements at the same level or higher as the most recent collapsed parent element + parent_is_collapsed = false; + return true; + } else if (!parent_is_collapsed) { + return true; + } + } + return false; + })(); + + if (is_target_to_update) { + var is_shown = el.is(':visible'); + if(target_shown == null){ + target_shown = is_shown; + target_top = + parseInt(subject.css('top')) + + parseInt(subject.data('collapse-expand').top_increment); + total_height = 0; + } + if(is_shown == target_shown){ + $(el_task_bars).each(function(_, task) { + var el_task = $(task); + if(!is_shown) + el_task.css('top', target_top + total_height); + if(!el_task.hasClass('tooltip')) + el_task.toggle(!is_shown); + }); + $(el_selected_columns).each(function (_, attr) { + var el_attr = $(attr); + if (!is_shown) + el_attr.css('top', target_top + total_height); + el_attr.toggle(!is_shown); + }); if(!is_shown) - el_task.css('top', target_top + total_height); - if(!el_task.hasClass('tooltip')) - el_task.toggle(!is_shown); - }); - $(el_selected_columns).each(function (_, attr) { - var el_attr = $(attr); - if (!is_shown) - el_attr.css('top', target_top + total_height); - el_attr.toggle(!is_shown); - }); - if(!is_shown) - el.css('top', target_top + total_height); - iconChange(el); - el.toggle(!is_shown); - total_height += parseInt(json.top_increment); + el.css('top', target_top + total_height); + if(!el.hasClass('collapsed') || force_collapse_expand) iconChange(el); + el.toggle(!is_shown); + total_height += parseInt(json.top_increment); + } } }); drawGanttHandler();