'use strict'; app .directive('optionClassExpr', function ($compile, $parse) { var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/; return { restrict: 'A', link: function optionClassExprPostLink(scope, elem, attrs) { var optionsExp = attrs.ngOptions; if (!optionsExp) return; var match = optionsExp.match(NG_OPTIONS_REGEXP); if (!match) return; var values = match[7]; scope.$watchCollection(function () { return elem.children(); }, function (newValue) { angular.forEach(newValue, function (child, index) { var child = angular.element(child); var val = child.val(); if (val) { child.attr('ng-class', values + '[' + (index - 1) + '].' + attrs.optionClassExpr); $compile(child)(scope); } }); }); } }; }) .directive('selectedSourceChanged', ['$timeout', function ($timeout) { return { link: function ($scope, element, attrs) { $scope.$on('selectedSourceChanged', function () { $timeout(function () { // You might need this timeout to be sure its run after DOM render. element.trigger("change"); }, 0, false); }) } }; }]) .controller('capacityManagementController', ['$scope', '$http', '$location', '$timeout', '$window', 'cellHighligting', function ($scope, $http, $location, $timeout, $window, cellHighligting) { $scope.CollapsedIcon = 'fa-plus-square'; $scope.NonCollapsedIcon = 'fa-minus-square'; $scope.ScenarioCollapsedIcon = 'fa-plus-square-1'; $scope.ScenarioNonCollapsedIcon = 'fa-minus-square-1'; $scope.ExpCatCollapsedIcon = 'fa-plus-square-2'; $scope.ExpCatNonCollapsedIcon = 'fa-minus-square-2'; $scope.id = $location.absUrl().substr($location.absUrl().lastIndexOf('ls/') + 3, 36); //$scope.data = { // VisibleCellCount: 1 //}; $scope.dataSection = ""; $scope.pageTitle = ""; // SA. ENV-905 $scope.preferences = []; $scope.headerWidth = 70; $scope.containerWidth = 0; $scope.firstColWidth = 0; $scope.calendarFilters = { CompanyId: null, StartDate: null, EndDate: null, ViewId: null, TeamId: null, ResourceId: null, IsUOMHours: null, PreferredTotalsDisplaying: null, ShowUpper: true, ShowLower: true, IsBarMode: true, ShowCapacity: 1, //"Total Allocated/Total Capacity" GroupByTeam: true, IsViewModeMonth: true, ShowAvgTotals: true, IsCapacityModeActuals: true, sortOrder: false, sortBy: 'Name' }; // SA. ENV-799 $scope.CalendarFilterMode = { IsCompany: true, IsView: false, IsTeam: false, IsResource: false, FilteredEntityTitle: "Company", SelectedItemId: null, } $scope.SpreadType = { Notspecified: -1, Equal: 0, Less: 1, Over: 2 }; $scope.availableFilterOptions = {}; $scope.data = null; $scope.data2Update = { ChangedExpCats: [] }; $scope.grandtotalrow = null; function getExpCatById(scenarioId, ExpCatId, teamId) { for (var i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].ExpCatId != null && $scope.data.Calendar[i].ScenarioId == scenarioId && $scope.data.Calendar[i].ExpCatId == ExpCatId && (!$scope.calendarFilters.GroupByTeam || $scope.data.Calendar[i].TeamId == teamId)) { return $scope.data.Calendar[i]; } } return null; } function getRowByType(type, expCatId) { for (var i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].RowType == type) { if (expCatId != null) { if ($scope.data.Calendar[i].ExpCatId == expCatId) return $scope.data.Calendar[i]; //return expCat by type+expCatId } else return $scope.data.Calendar[i]; //return expCat by type } } return null; } function getResourceById(resId) { for (var i = 0; i < $scope.data.AllResources.length; i++) { if ($scope.data.AllResources[i].Id == resId) { return $scope.data.AllResources[i]; } } return null; } function getResourceByExpCat(expCat, resId) { if (expCat != null) { for (var i = 0; i < expCat.Resources.length; i++) { if (expCat.Resources[i].Id == resId) { return expCat.Resources[i]; } } } return null; } function setChildrenCollapsed(row, internal, parentCollapsed) { var isProject = row.ProjectId != null && row.ExpCatId == null; var isExpCat = row.ExpCatId != null; for (var i = 0; i < $scope.data.Calendar.length; i++) { var currRow = $scope.data.Calendar[i]; if (isProject && currRow.ExpCatId != null && currRow.ProjectId == row.ProjectId && (!$scope.calendarFilters.GroupByTeam || currRow.TeamId == row.TeamId)) { var expCat = currRow; if (internal) { expCat.IsParentCollapsed = parentCollapsed; setChildrenCollapsed(expCat, true, parentCollapsed); } else { expCat.IsParentCollapsed = row.ProjectCollapsed; setChildrenCollapsed(expCat, true, row.ProjectCollapsed); } } else if (isExpCat && currRow.ExpCatId == row.ExpCatId && currRow.ScenarioId == row.ScenarioId && (!$scope.calendarFilters.GroupByTeam || currRow.TeamId == row.TeamId)) { var resource = currRow; if (internal) { resource.IsParentCollapsed = parentCollapsed; } } } } function clearResource(scenarioId, expCatId, resource, teamId) { if (resource != null) { for (var i = 0; i < $scope.data.Headers.length; i++) { changeResourceValue(0, scenarioId, expCatId, resource.Id, teamId, i); } } } function updateTotals(expCat, expCatTotal, resourceTotal, resource, colIndex, newQuantity, oldQuantity, newCost, oldCost) { var monthStartIndex = 0; var monthEndIndex = colIndex; var weeks = 0; for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) { if (!$scope.data.Headers[i].IsMonth) { monthEndIndex++; } else { weeks = $scope.data.Headers[i].Weeks.length; monthStartIndex = monthEndIndex - weeks + 1; break; } } var total = 0; var monthTotalCellIndex = monthEndIndex + 1; oldQuantity = resource.QuantityValues[monthTotalCellIndex]; for (var i = monthStartIndex; i < monthTotalCellIndex; i++) { if (colIndex == i) total += newQuantity; else total += resource.QuantityValues[i]; } if ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours) { newQuantity = Math.round(total / weeks * 1000) / 1000; } else { //update month cell //resource.QuantityValues[i] += (newQuantity - oldQuantity); newQuantity = total; } resource.QuantityValues[monthTotalCellIndex] = newQuantity; if (resourceTotal != null) { resourceTotal.QuantityValues[monthTotalCellIndex] += (newQuantity - oldQuantity); expCatTotal.QuantityValues[monthTotalCellIndex] += (newQuantity - oldQuantity); } recalcSpreading(expCat, expCatTotal, resourceTotal, monthTotalCellIndex); updateCSSClass(expCat, resource, colIndex); } function GetAssignedResCount() { var resIds = ""; var res = 0; for (var i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].ExpCatId != null && $scope.data.Calendar[i].ScenarioId != null) { for (var j = 0; j < $scope.data.Calendar[i].Resources.length; j++) { var resId = $scope.data.Calendar[i].Resources[j].Id; if (resIds.indexOf(resId + ",") == -1) { resIds += resId + ","; res++; } } } } return res; } function allocateResource(resource, expCat, create, allocateRest, reset) { if (resource != null) { var scenarioCalendarRow = null; var i; for (i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].ExpCatId == expCat.ExpCatId && $scope.data.Calendar[i].ScenarioId == expCat.ScenarioId) { scenarioCalendarRow = $scope.data.Calendar[i]; break; } } var team = null; for (i = 0; i < expCat.Teams.length; i++) { if (expCat.Teams[i].Id == resource.TeamId) { team = expCat.Teams[i]; break; } } var res = getResourceById(resource.Id); for (i = 0; i < $scope.data.Headers.length; i++) { if ($scope.data.Headers[i].IsMonth || resource.ReadOnlyWeeks[i]) continue; var needToAssign = Math.max(team.QuantityValues[i] - team.AllocatedByResources[i], 0); var quantity = 0; if (create || reset) //Reset { if (create) resource.QuantityValues[i] = 0; quantity = 0; } else if (allocateRest) { //AssignRest var canBeAssigned = Math.max(res.CapacityQuantityValues[i] - res.AllocatedQuantityValues[i], 0); quantity = Math.min(needToAssign, canBeAssigned); if (quantity == 0) { continue; } quantity += resource.QuantityValues[i]; } else { //AssignAll var canBeAssigned = Math.max(res.CapacityQuantityValues[i] - res.AllocatedQuantityValues[i], 0); quantity = Math.min(needToAssign, canBeAssigned); if (quantity == 0) { continue; } quantity += resource.QuantityValues[i]; } changeResourceValue(quantity, expCat.ScenarioId, expCat.ExpCatId, resource.Id, resource.TeamId, i); } } } function recalcSpreading(expCat, expCatTotal, resourceTotal, colIndex) { var i; if (expCat != null) { var scenarioCalendarRow = null; for (i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].ProjectId == expCat.ProjectId && $scope.data.Calendar[i].ExpCatId == null && $scope.data.Calendar[i].ScenarioId == expCat.ScenarioId) { scenarioCalendarRow = $scope.data.Calendar[i]; break; } } var resTotal = 0; for (i = 0; i < expCat.Resources.length; i++) { resTotal += expCat.Resources[i].QuantityValues[colIndex]; } //resTotal = Math.round(resTotal * 1000000) / 1000000; var compareRes = cellHighligting.compare(resTotal, expCat.QuantityValues[colIndex]); expCat.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over : compareRes < 0 ? $scope.SpreadType.Less : compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified; updateCSSClass(expCat, null, colIndex); var projectClass = $scope.SpreadType.Equal; for (i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].ProjectId == expCat.ProjectId && $scope.data.Calendar[i].ExpCatId != null && $scope.data.Calendar[i].ScenarioId == expCat.ScenarioId && (!$scope.calendarFilters.GroupByTeam || $scope.data.Calendar[i].TeamId == expCat.TeamId)) { if ($scope.data.Calendar[i].SpreadVal[colIndex] == $scope.SpreadType.Over) { projectClass = $scope.SpreadType.Over; break; } else if ($scope.data.Calendar[i].SpreadVal[colIndex] == $scope.SpreadType.Less) { projectClass = $scope.SpreadType.Less; } } } scenarioCalendarRow.SpreadVal[colIndex] = projectClass; updateCSSClass(scenarioCalendarRow, null, colIndex); } //calc exp cat total row if (expCatTotal != null) { //var expCatSpread = $scope.SpreadType.Equal; for (i = 0; i < expCatTotal.Resources.length; i++) { var res = expCatTotal.Resources[i]; var resValue = res.QuantityTotalResValue[colIndex]; //expCatTotal.QuantityTotalResValue[colIndex]; var compareRes = cellHighligting.compare(res.QuantityValues[colIndex], resValue); var compareResAndEc = cellHighligting.compare(res.QuantityValues[colIndex], expCatTotal.QuantityValues[colIndex]); res.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over : compareRes < 0 ? $scope.SpreadType.Less : compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified; updateCSSClass(expCatTotal, res, colIndex); } if (expCat != null && expCat.Resources != null) { for (i = 0; i < expCat.Resources.length; i++) { var res = expCat.Resources[i]; var resValue = expCat.QuantityValues[colIndex]; var compareRes = cellHighligting.compare(res.QuantityValues[colIndex], resValue); res.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over : compareRes < 0 ? $scope.SpreadType.Less : compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified; updateCSSClass(expCat, res, colIndex); } } var resValue = expCatTotal.QuantityTotalResValue[colIndex]; var compareRes = cellHighligting.compare(expCatTotal.QuantityValues[colIndex], resValue); expCatTotal.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over : compareRes < 0 ? $scope.SpreadType.Less : compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified; updateCSSClass(expCatTotal, null, colIndex); } } function updateCSSClass(row, resRow, colIndex) { if (resRow == null) { // updating project/scenario/category row if (row == null || colIndex == null || row.SpreadVal == null || row.SpreadVal.length <= colIndex) return; row.CSSClass[colIndex] = (row.CSSClass[colIndex] || '').replace(/cellover/g, '').replace(/cellless/g, '').replace(/cellequal/g, '');; if (!row.ReadOnly[colIndex]) { if (row.SpreadVal[colIndex] == $scope.SpreadType.Equal) row.CSSClass[colIndex] = 'cellequal'; else if (row.SpreadVal[colIndex] == $scope.SpreadType.Over) row.CSSClass[colIndex] = 'cellover'; else if (row.SpreadVal[colIndex] == $scope.SpreadType.Less) row.CSSClass[colIndex] = 'cellless'; if (row.RowType == 0) { if (row.Color != null && row.Color.length > 0 && $scope.calendarFilters.IsBarMode) { row.BarStyle[colIndex] = "border-bottom: 1px solid " + row.Color + " !important;border-right-color: " + row.Color + " !important;background-color: " + row.Color + ";"; } else { row.BarStyle[colIndex] = null; } } } if ((row.ProjectId == null && row.ExpCatId != null && $scope.calendarFilters.ShowCapacity == 1) || (row.ProjectId == null && row.ExpCatId != null && $scope.calendarFilters.ShowCapacity == 2) || (row.ProjectId == null && row.ExpCatId != null && $scope.calendarFilters.ShowCapacity == 3)) row.CSSClass[colIndex] += ' capacity-total'; // assign more classes if needed } else { // updating resource row if (row == null || colIndex == null || row.ReadOnly[colIndex]) return; if (resRow.SpreadVal == null || resRow.SpreadVal.length <= colIndex) return; resRow.CSSClass[colIndex] = (resRow.CSSClass[colIndex] || '').replace(/cellover/g, '').replace(/cellless/g, '').replace(/cellequal/g, '');; if (resRow.SpreadVal[colIndex] == $scope.SpreadType.Equal) resRow.CSSClass[colIndex] = 'cellequal'; else if (resRow.SpreadVal[colIndex] == $scope.SpreadType.Over) resRow.CSSClass[colIndex] = 'cellover'; else if (resRow.SpreadVal[colIndex] == $scope.SpreadType.Less) resRow.CSSClass[colIndex] = 'cellless'; // assign more classes if needed } } function recalcRest(expCat, colIndex) { var sum = 0; for (var i = 0; i < expCat.Resources.length; i++) { sum += expCat.Resources[i].QuantityValues[colIndex]; } if (expCat.QuantityValues[colIndex] < sum) expCat.RestQuantity[colIndex] = 0; else expCat.RestQuantity[colIndex] = expCat.QuantityValues[colIndex] - sum; } function changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex) { var expCat = getExpCatById(scenarioId, expCatId, teamId); var expCatTotal = getExpCatById(null, expCatId, null); var resource = getResourceByExpCat(expCat, resId); var resourceTotal = getResourceByExpCat(expCatTotal, resId); if (expCat != null && resource != null) { var team = null; for (var i = 0; i < expCat.Teams.length; i++) { if (expCat.Teams[i].Id == resource.TeamId) { team = expCat.Teams[i]; break; } } var res = getResourceById(resource.Id); team.AllocatedByResources[colIndex] += (newValue - resource.QuantityValues[colIndex]); res.AllocatedQuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]); resource.GrandTotalQuantity += (newValue - resource.QuantityValues[colIndex]); updateTotals(expCat, expCatTotal, resourceTotal, resource, colIndex, newValue, resource.QuantityValues[colIndex], 0, 0); //expCat.RestQuantity[colIndex] -= newValue - resource.QuantityValues[colIndex]; if (expCatTotal != null && resourceTotal != null) { resourceTotal.QuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]); expCatTotal.QuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]); } resource.QuantityValues[colIndex] = newValue; recalcRest(expCat, colIndex); applyCellChange(scenarioId, expCatId, $scope.data.Headers[colIndex].Milliseconds, expCat.DetailIds[colIndex], newValue, 0, resId, false, false); } recalcSpreading(expCat, expCatTotal, resourceTotal, colIndex); updateCSSClass(expCat, resource, colIndex); } function applyCellChange(scenarioId, rowId, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved) { var catIndex = -1; for (var ix = 0; ix < $scope.data2Update.ChangedExpCats.length; ix++) { if ($scope.data2Update.ChangedExpCats[ix].Id == rowId && $scope.data2Update.ChangedExpCats[ix].ScenarioId == scenarioId) { catIndex = ix; break; } } if (catIndex == -1) { $scope.data2Update.ChangedExpCats[$scope.data2Update.ChangedExpCats.length] = { ScenarioId: scenarioId, Id: rowId, Values: [], Resources: [] }; catIndex = $scope.data2Update.ChangedExpCats.length - 1; } if (resId == null) { var dateIndex = -1; for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Values.length; dx++) { if ($scope.data2Update.ChangedExpCats[catIndex].Values[dx].Id == cellId) { dateIndex = dx; break; } } if (dateIndex == -1) { $scope.data2Update.ChangedExpCats[catIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Values.length] = { Id: cellId, Milliseconds: cellMilliseconds, Values: [] }; dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Values.length - 1; } //$scope.data2Update.ChangedExpCats[catIndex].Values[dateIndex].Cost = cellCost; $scope.data2Update.ChangedExpCats[catIndex].Values[dateIndex].Quantity = cellQuantity; } else { var dateIndex = -1; for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources.length; dx++) { if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dx].Id == resId) { dateIndex = dx; break; } } if (dateIndex == -1) { $scope.data2Update.ChangedExpCats[catIndex].Resources[$scope.data2Update.ChangedExpCats[catIndex].Resources.length] = { Id: resId, Values: [], IsAdded: isAdded, IsRemoved: isRemoved }; dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources.length - 1; if (isAdded || isRemoved) return; } else { if (isRemoved) { if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].IsAdded) { $scope.data2Update.ChangedExpCats[catIndex].Resources.splice(dateIndex, 1); } return; } } var dateIndex1 = -1; for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length; dx++) { if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dx].Milliseconds == cellMilliseconds) { dateIndex1 = dx; break; } } if (dateIndex1 == -1) { $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length] = { Id: cellId, Milliseconds: cellMilliseconds, Values: [] }; dateIndex1 = $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length - 1; } //$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Cost = cellCost; $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Quantity = cellQuantity; } } function refreshTotalSpreadVal(expCatTotal) { if (expCatTotal.RowType == 7) { for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { var resValue = expCatTotal.QuantityTotalResValue[colIndex]; var total = 0; var allocated = 0; if ($scope.calendarFilters.ShowCapacity == 1) { allocated = expCatTotal.QuantityValues[colIndex]; total = expCatTotal.QuantityTotalResValue[colIndex]; } else if ($scope.calendarFilters.ShowCapacity == 2) { allocated = expCatTotal.QuantityExpCatTotalValue[colIndex]; total = expCatTotal.QuantityTotalResValue[colIndex]; } else { allocated = expCatTotal.QuantityValues[colIndex]; total = expCatTotal.QuantityExpCatTotalValue[colIndex]; } var compareRes = cellHighligting.compare(allocated, total); expCatTotal.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over : compareRes < 0 ? $scope.SpreadType.Less : compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified; // this code sets Equal by default. It means that 2 zeros will be displayed as green // so I decided to remove it to keep zeros without highligthing //var expCatSpread = $scope.SpreadType.Equal; //if (expCatTotal.SpreadVal[colIndex] == $scope.SpreadType.Over) { // expCatSpread = $scope.SpreadType.Over; //} else if (expCatTotal.SpreadVal[colIndex] == $scope.SpreadType.Less) { // expCatSpread = $scope.SpreadType.Less; //} //expCatTotal.SpreadVal[colIndex] = expCatSpread; updateCSSClass(expCatTotal, null, colIndex); } } //updateCSSClass(expCatTotal, null, colIndex); } function initCmMenuItems() { var menu = $('#' + $scope.calendarFilters.MenuId); menu.html(""); $.each($("#menuCalendarOptionsPrint li"), function (i, o) { $(o).appendTo(menu); }); $.each($("#menuCalendarOptions li"), function (i, o) { $(o).clone(true).appendTo(menu).change(function () { if (typeof onCMPreferencesItemClick === 'function') onCMPreferencesItemClick(menu); }); }); // SA. ENV-815 $("#menuCalendarOptions").find('*[data-key]').removeAttr('data-key'); } $scope.init = function (initData) { $scope.calendarFilters.ShowUpper = initData.ShowUpper; $scope.calendarFilters.ShowLower = initData.ShowLower; $scope.calendarFilters.IsUOMHours = initData.IsUOMHours; $scope.calendarFilters.PreferredTotalsDisplaying = initData.PreferredTotalsDisplaying; $scope.calendarFilters.IsBarMode = initData.IsBarMode; $scope.calendarFilters.IsViewModeMonth = initData.IsViewModeMonth; $scope.calendarFilters.IsCapacityModeActuals = initData.IsCapacityModeActuals; $scope.calendarFilters.GroupByTeam = initData.GroupByTeam; $scope.calendarFilters.ShowCapacity = initData.ShowCapacity; $scope.calendarFilters.StartDate = initData.StartDate; $scope.calendarFilters.EndDate = initData.EndDate; $scope.calendarFilters.ModelType = initData.ModelType; $scope.calendarFilters.MenuId = initData.MenuId; $scope.dataSection = initData.DataSection; $scope.pageTitle = initData.PageTitle; // SA. ENV-905 $scope.availableFilterOptions = initData.FilterOptions; // SA. ENV-799 initCmMenuItems(); var pagePrefArray; if (initData.PagePreferences && initData.PagePreferences.length > 0) { // SA. ENV-799 var filterModeInit = ""; var filterSelectedItemId = null; pagePrefArray = JSON.parse(initData.PagePreferences); $scope.preferences = pagePrefArray; for (var i = 0; i < pagePrefArray.length; i++) { switch (pagePrefArray[i].Key) { case "showChart": $scope.calendarFilters.ShowUpper = pagePrefArray[i].Value; break; case "showCriteria": $scope.calendarFilters.ShowLower = pagePrefArray[i].Value; break; case "showOption": $scope.calendarFilters.ShowCapacity = pagePrefArray[i].Value != null ? pagePrefArray[i].Value : 1; //"Total Allocated/Total Need"; break; case "uomMode": $scope.calendarFilters.IsUOMHours = pagePrefArray[i].Value; break; case "capBarMode": $scope.calendarFilters.IsBarMode = pagePrefArray[i].Value; break; case "defaultView": $scope.calendarFilters.IsViewModeMonth = pagePrefArray[i].Value; break; case "groupByTeam": if ($scope.calendarFilters.ModelType != 'TeamboardModel') $scope.calendarFilters.GroupByTeam = pagePrefArray[i].Value; else $scope.calendarFilters.GroupByTeam = false; break; case "capacityView": $scope.calendarFilters.IsCapacityModeActuals = pagePrefArray[i].Value; break; case "capacityFilterStartDate": $scope.calendarFilters.StartDate = pagePrefArray[i].Value; break; case "capacityFilterEndDate": $scope.calendarFilters.EndDate = pagePrefArray[i].Value; break; case "filterCompanyList": if ((pagePrefArray[i].Value) && (filterModeInit.length < 1)) filterModeInit = "Company"; break; case "filterViewList": if ((pagePrefArray[i].Value) && (filterModeInit.length < 1)) filterModeInit = "View"; break; case "filterTeamList": if ((pagePrefArray[i].Value) && (filterModeInit.length < 1)) filterModeInit = "Team"; break; case "filteredCompany": filterSelectedItemId = pagePrefArray[i].Value; break; case "sortBy": $scope.calendarFilters.sortBy = pagePrefArray[i].Value; break; case "sortOrder": $scope.calendarFilters.sortOrder = pagePrefArray[i].Value; break; default: console.log("Restore page preferences (Activity calendar): data key not found in parsing loaded preferences (datakey=" + pagePrefArray[i].Key + ", dataSection=" + $scope.dataSection + ")"); } } } pagePrefArray = []; pagePrefArray.push({ Key: "showChart", Value: $scope.calendarFilters.ShowUpper }); pagePrefArray.push({ Key: "showCriteria", Value: $scope.calendarFilters.ShowLower }); pagePrefArray.push({ Key: "sortBy", Value: $scope.calendarFilters.sortBy }); pagePrefArray.push({ Key: "sortOrder", Value: $scope.calendarFilters.sortOrder }); pagePrefArray.push({ Key: "showOption", Value: $scope.calendarFilters.ShowCapacity }); pagePrefArray.push({ Key: "uomMode", Value: $scope.calendarFilters.IsUOMHours }); pagePrefArray.push({ Key: "capBarMode", Value: $scope.calendarFilters.IsBarMode }); pagePrefArray.push({ Key: "defaultView", Value: $scope.calendarFilters.IsViewModeMonth }); pagePrefArray.push({ Key: "groupByTeam", Value: $scope.calendarFilters.GroupByTeam }); pagePrefArray.push({ Key: "capacityView", Value: $scope.calendarFilters.IsCapacityModeActuals }); pagePrefArray.push({ Key: "capacityFilterStartDate", Value: $scope.calendarFilters.StartDate }); pagePrefArray.push({ Key: "capacityFilterEndDate", Value: $scope.calendarFilters.EndDate }); // pagePrefArray.push({ Key: "filteredCompany", Value: $scope.calendarFilters.CompanyId }); restorePreferences($scope.dataSection, pagePrefArray); $('#' + $scope.calendarFilters.MenuId).click(function (event) { event.stopPropagation(); }); // SA. ENV-799 if ($scope.IsEmpty(initData.CompanyId) && $scope.IsEmpty(initData.ViewId) && $scope.IsEmpty(initData.TeamId) && $scope.IsEmpty(initData.ResourceId)) { if (filterModeInit == "Company") initData.CompanyId = filterSelectedItemId; if (filterModeInit == "View") initData.ViewId = filterSelectedItemId; if (filterModeInit == "Team") initData.TeamId = filterSelectedItemId; if (filterModeInit == "Resource") initData.ResourceId = filterSelectedItemId; } var filterAttached = false; // if ($scope.calendarFilters.ModelType && ($scope.calendarFilters.ModelType == "EnVisage.Models.CapacityDetailsModel")) { if (initData.CompanyId && (initData.CompanyId.length > 0)) { $scope.CalendarFilterMode.SelectedItemId = initData.CompanyId; $scope.switchCompanyFilterMode(true); filterAttached = true; } if (initData.ViewId && (initData.ViewId.length > 0)) { $scope.CalendarFilterMode.SelectedItemId = initData.ViewId; $scope.switchViewFilterMode(true); filterAttached = true; } if (initData.TeamId && (initData.TeamId.length > 0)) { $scope.CalendarFilterMode.SelectedItemId = initData.TeamId; $scope.switchTeamFilterMode(true); filterAttached = true; } if (initData.ResourceId && (initData.ResourceId.length > 0)) { $scope.CalendarFilterMode.SelectedItemId = initData.ResourceId; $scope.switchResourceFilterMode(true); filterAttached = true; } if (!filterAttached) { $scope.switchCompanyFilterMode(); } // } // SA. ENV-799 $scope.loadCalendarData(); }; $scope.IsEmpty = function (value) { return !value || (value == null) || (value == ""); } $scope.getCalendar = function () { $("#loader").hide(); if ($scope.IsEmpty($scope.calendarFilters.CompanyId) && $scope.IsEmpty($scope.calendarFilters.TeamId) && $scope.IsEmpty($scope.calendarFilters.ViewId) && $scope.IsEmpty($scope.calendarFilters.ResourceId)) { return; } blockUI(); $scope.data = null; $("#loader").show(); var postData = JSON.parse(JSON.stringify($scope.calendarFilters)); $http.post('/CapacityManagement/LoadJsonCalendar', postData). success(function (data, status, headers, config) { if (data == null) $("#loader").hide(); if (data != null && data.Headers == null || data.Headers.length < 1) { $("#loader").hide(); unblockUI(); return; } $scope.data = data; $scope.calendarFilters.ShowAvgTotals = data.PreferredTotalsDisplaying; $scope.calendarFilters.IsUOMHours = data.IsUOMHours; swithViewMode(); for (var i = 0; i < $scope.data.Calendar.length; i++) { $scope.data.Calendar[i].IsUpperHidden = !$scope.calendarFilters.ShowUpper; $scope.data.Calendar[i].IsLowerHidden = !$scope.calendarFilters.ShowLower; } // initial setup css classes for (var rowIndex = 0; rowIndex < $scope.data.Calendar.length; rowIndex++) { if ($scope.data.Calendar[rowIndex].CSSClass == null) $scope.data.Calendar[rowIndex].CSSClass = new Array($scope.data.Headers.length); if ($scope.data.Calendar[rowIndex].BarStyle == null) $scope.data.Calendar[rowIndex].BarStyle = new Array($scope.data.Headers.length); refreshTotalSpreadVal($scope.data.Calendar[rowIndex]); for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { if ($scope.data.Calendar[rowIndex].RowType != 7) updateCSSClass($scope.data.Calendar[rowIndex], null, colIndex); if ($scope.data.Calendar[rowIndex].Resources != null && $scope.data.Calendar[rowIndex].Resources.length > 0) { for (var resIndex = 0; resIndex < $scope.data.Calendar[rowIndex].Resources.length; resIndex++) { if ($scope.data.Calendar[rowIndex].Resources[resIndex].CSSClass == null) $scope.data.Calendar[rowIndex].Resources[resIndex].CSSClass = new Array($scope.data.Headers.length); updateCSSClass($scope.data.Calendar[rowIndex], $scope.data.Calendar[rowIndex].Resources[resIndex], colIndex); } } } } for (i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].IsTotals && $scope.data.Calendar[i].RowType == 5) { $scope.grandtotalrow = $scope.data.Calendar[i]; break; } } $("#loader").hide(); unblockUI(); }). error(function (data, status, headers, config) { // called asynchronously if an error occurs // or server returns response with an error status. console.log("an error occurred while loading calendar"); $("#loader").hide(); unblockUI(); }); }; $scope.checkEditable = function (useType) { if (3 === useType) { return false; } return true; }; $scope.watchKeyInput = function (t) { $timeout(function () { if (t.$editable.inputEl.select) t.$editable.inputEl.select(); else if (t.$editable.inputEl.setSelectionRange) t.$editable.inputEl.setSelectionRange(0, t.$editable.inputEl.val().length); }, 3); t.$editable.inputEl.on('keydown', function (e) { if (e.which == 9) { //when tab key is pressed e.preventDefault(); var tab2Cell; if (e.shiftKey) { // when shift + tab use with 'onblur' set to 'submit' for automatic submission find the parent of the editable before this one in the markup grab the editable and display it tab2Cell = $(this).parentsUntil('table#table').prevAll(":has(.editable:visible):first").find(".editable:visible:last"); t.$form.$submit(); tab2Cell.click(); } else { // when just tab use with 'onblur' set to 'submit' for automatic submission find the parent of the editable after this one in the markup grab the editable and display it tab2Cell = $(this).parentsUntil('table#table').nextAll(":has(.editable:visible):first").find(".editable:visible:first"); t.$form.$submit(); tab2Cell.click(); } } }); }; $scope.onTxtBlur = function (txt) { txt.$form.$submit(); }; $scope.saveChanges = function () { blockUI(); var postData = JSON.parse(JSON.stringify($scope.data2Update)); postData.ScenarioFilters = $scope.calendarFilters; $http.post('/CapacityManagement/SaveChanges', postData). success(function (data, status, headers, config) { $scope.data2Update = { ScenarioId: $scope.id, ChangedExpCats: [] }; // alert("data saved successfully"); //var tab = $("#uidemo-tabs-default-demo li.active a").attr("href"); //var retUrl = window.location.href; //if (retUrl.indexOf("&tab=") > 0) { // retUrl = retUrl.substr(0, retUrl.indexOf("&tab=")); //} //window.location.href = retUrl; // + "&tab=" + tab.replace("#", ""); $scope.getCalendar(); unblockUI(); }). error(function (data, status, headers, config) { console.log("an error occurred while saving calendar changes"); unblockUI(); }); }; $scope.takeAll = function (scenarioId, resId, expCatId, teamId) { var expCat = getExpCatById(scenarioId, expCatId, teamId); if (expCat != null) { var create = false; var allocateRest = false; var reset = false; allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset); } }; $scope.takeRemaining = function (scenarioId, resId, expCatId, teamId) { var expCat = getExpCatById(scenarioId, expCatId, teamId); if (expCat != null) { var create = false; var allocateRest = true; var reset = false; allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset); //false, true, false); } }; $scope.zeroResource = function (scenarioId, resId, expCatId, teamId) { if (confirm("Are you sure you want fill this resource quantities with 0s?")) { var expCat = getExpCatById(scenarioId, expCatId, teamId); var create = false; var allocateRest = false; var reset = true; allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset); //false, false, true); } }; $scope.assignResource = function (resId, scenarioId, expCatId, teamId, $event) { if (resId == null || expCatId == null || teamId == null) return; var resource = getResourceById(resId); if (resource != null) { var expCat = getExpCatById(scenarioId, expCatId, teamId); var expCatTotal = getExpCatById(null, expCatId, null); var rowCapacity = getRowByType(6); var rowVacation = getRowByType(2); var rowTraining = getRowByType(3); //Check the same resource assignment if (getResourceByExpCat(expCat, resource.Id) != null) { alert("The " + resource.Name + " has been assigned to the " + expCat.Name); return; } //Add exp cat resource //todo: just added resources are not validated against capacity values var newResource = { 'Id': resource.Id, 'Name': resource.Name, 'QuantityValues': new Array($scope.data.Headers.length), 'SpreadVal': new Array($scope.data.Headers.length), 'CSSClass': new Array($scope.data.Headers.length), 'CapacityQuantityValues': new Array($scope.data.Headers.length), 'AllocatedQuantityValues': new Array($scope.data.Headers.length), 'ReadOnlyWeeks': new Array($scope.data.Headers.length), 'TeamId': resource.TeamId }; var i; for (i = 0; i < newResource.QuantityValues.length; i++) { if (isNaN(newResource.QuantityValues[i])) newResource.QuantityValues[i] = 0; } expCat.Resources.push(newResource); if (expCatTotal != null) { var resourceTotal = getResourceByExpCat(expCatTotal, resource.Id); var colIndex; if (resourceTotal == null) { //Add total exp cat resource resourceTotal = { 'Id': resource.Id, 'Name': resource.Name, 'QuantityValues': new Array($scope.data.Headers.length), 'SpreadVal': new Array($scope.data.Headers.length), 'CSSClass': new Array($scope.data.Headers.length) }; for (i = 0; i < resourceTotal.QuantityValues.length; i++) { if (isNaN(resourceTotal.QuantityValues[i])) resourceTotal.QuantityValues[i] = 0; } expCatTotal.QuantityTotalResValue = expCatTotal.QuantityResValue * (expCatTotal.Resources.length + 1); expCatTotal.Resources.push(resourceTotal); for (colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { if (rowCapacity != null) { rowCapacity.QuantityValues[colIndex] += expCatTotal.QuantityResValue; } } } var monthVacation = 0; var monthTraining = 0; var assignedResCount = 1; //GetAssignedResCount(); for (colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { if (!$scope.data.Headers[colIndex].IsMonth) { if (rowVacation != null) { rowVacation.QuantityValues[colIndex] += resource.VacationQuantityValues[colIndex]; monthVacation += rowVacation.QuantityValues[colIndex]; } if (rowTraining != null) { rowTraining.QuantityValues[colIndex] += resource.TrainingQuantityValues[colIndex]; monthTraining += rowTraining.QuantityValues[colIndex]; } newResource.CapacityQuantityValues[colIndex] = expCatTotal.QuantityResValue - resource.VacationQuantityValues[colIndex] - resource.TrainingQuantityValues[colIndex]; newResource.ReadOnlyWeeks[colIndex] = resource.ReadOnlyWeeks[colIndex]; } else { if ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours) { monthVacation = Math.round(monthVacation / $scope.data.Headers[colIndex].Weeks.length / assignedResCount * 1000) / 1000; monthTraining = Math.round(monthTraining / $scope.data.Headers[colIndex].Weeks.length / assignedResCount * 1000) / 1000; } else { } $scope.grandtotalrow.QuantityValues[colIndex] += -(rowVacation.QuantityValues[colIndex] + rowTraining.QuantityValues[colIndex]) + monthVacation + monthTraining; rowVacation.QuantityValues[colIndex] = monthVacation; rowTraining.QuantityValues[colIndex] = monthTraining; monthTraining = 0; monthVacation = 0; } } } var create = true; var allocateRest = false; var reset = false; allocateResource(newResource, expCat, create, allocateRest, reset); //true, false, false); expCatTotal.EmptyScenario = expCatTotal.Resources.length == 0; //todo: remove var tr = $($event.target).parentsUntil('table').last().parent().find('thead tr:first'); console.log("tr: " + $(tr).html()); var thName = tr.find('th:eq(0)'); console.log("thName: " + $(thName).html()); newResource.width = thName.width() + 'px'; } }; $scope.removeResource = function (scenarioId, resId, expCatId, teamId) { if (confirm("Are you sure you want to remove this resource?")) { var expCat = getExpCatById(scenarioId, expCatId, teamId); var expCatTotal = getExpCatById(null, expCatId, null); var rowVacation = getRowByType(2); var rowTraining = getRowByType(3); var resource = getResourceById(resId); for (var i = 0; i < expCat.Resources.length; i++) { if (expCat.Resources[i].Id == resId) { for (var k = 0; k < expCat.QuantityValues.length; k++) { //expCat.RestQuantity[k] += expCat.Resources[i].QuantityValues[k]; changeResourceValue(0, expCat.ScenarioId, expCat.ExpCatId, expCat.Resources[i].Id, expCat.Resources[i].TeamId, k); } expCat.Resources.splice(i, 1); var monthVacation = 0; var monthTraining = 0; var assignedResCount = 1; //GetAssignedResCount(); for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { if (!$scope.data.Headers[colIndex].IsMonth) { if (rowVacation != null) { rowVacation.QuantityValues[colIndex] += resource.VacationQuantityValues[colIndex]; monthVacation += rowVacation.QuantityValues[colIndex]; } if (rowTraining != null) { rowTraining.QuantityValues[colIndex] += resource.TrainingQuantityValues[colIndex]; monthTraining += rowTraining.QuantityValues[colIndex]; } //newResource.CapacityQuantityValues[colIndex] = expCatTotal.QuantityResValue - resource.VacationQuantityValues[colIndex] - resource.TrainingQuantityValues[colIndex]; } else { if ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours) { monthVacation = Math.round(monthVacation / $scope.data.Headers[colIndex].Weeks.length / assignedResCount * 1000) / 1000; monthTraining = Math.round(monthTraining / $scope.data.Headers[colIndex].Weeks.length / assignedResCount * 1000) / 1000; } else { //rowVacation.QuantityValues[colIndex] = monthVacation; //rowTraining.QuantityValues[colIndex] = monthTraining; } $scope.grandtotalrow.QuantityValues[colIndex] += -(rowVacation.QuantityValues[colIndex] + rowTraining.QuantityValues[colIndex]) + monthVacation + monthTraining; rowVacation.QuantityValues[colIndex] = monthVacation; rowTraining.QuantityValues[colIndex] = monthTraining; monthTraining = 0; monthVacation = 0; } } applyCellChange(scenarioId, expCatId, 0, 0, 0, 0, resId, false, true); expCatTotal.EmptyScenario = expCatTotal.Resources.length == 0; for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { if (rowVacation != null) { rowVacation.QuantityValues[colIndex] -= resource.VacationQuantityValues[colIndex]; if (rowVacation.QuantityValues[colIndex] < 0) rowVacation.QuantityValues[colIndex] = 0; } if (rowTraining != null) { rowTraining.QuantityValues[colIndex] -= resource.TrainingQuantityValues[colIndex]; if (rowTraining.QuantityValues[colIndex] < 0) rowTraining.QuantityValues[colIndex] = 0; } } return; } } } }; $scope.checkResourceValue = function (data, scenarioId, expCatId, resId, teamId, colIndex) { var newValue = parseFloat(data); if (isNaN(newValue)) newValue = 0; if (newValue < 0) { return "Value should not be less than zero"; } var expCat = getExpCatById(scenarioId, expCatId, teamId); var resource = getResourceByExpCat(expCat, resId); var isMonth = $scope.data.Headers[colIndex].IsMonth; if (isMonth) { var ec_val = resource.QuantityValues[colIndex]; var weeks = 0; for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) { weeks++; } var oldValue = ec_val; var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours); var coef = avg ? (newValue / oldValue) : (ec_val > 0 ? newValue / ec_val : 1); for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) { var val = avg ? (ec_val > 0 ? resource.QuantityValues[j] * coef : newValue) : (ec_val > 0 ? resource.QuantityValues[j] * coef : newValue / weeks); changeResourceValue(val, scenarioId, expCatId, resId, teamId, j); } //changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex); } else { changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex); } return false; }; $scope.getExpCatResources = function (expCat) { var resources = []; for (var i = 0; i < $scope.data.AllResources.length; i++) { if ($scope.data.AllResources[i].ExpedentureCategoryId == expCat.ExpCatId && $scope.data.AllResources[i].IsActiveEmployee) { var isProjectFound = false; for (var j = 0; j < $scope.data.AllResources[i].ProjectIds.length; j++) { if ($scope.data.AllResources[i].ProjectIds[j] == expCat.ProjectId && (!$scope.calendarFilters.GroupByTeam || $scope.data.AllResources[i].TeamId == expCat.TeamId)) { isProjectFound = true; break; } } if (isProjectFound) { var isFound = false; for (var j = 0; j < expCat.Resources.length; j++) { if (expCat.Resources[j].Id == $scope.data.AllResources[i].Id && (!$scope.calendarFilters.GroupByTeam || expCat.Resources[j].TeamId == $scope.data.AllResources[i].TeamId)) { isFound = true; break; } } if (!isFound) { for (var j = 0; j < resources.length; j++) { if (resources[j].Id == $scope.data.AllResources[i].Id && (!$scope.calendarFilters.GroupByTeam || resources[j].TeamId == $scope.data.AllResources[i].TeamId)) { isFound = true; break; } } } if (!isFound && $scope.data.AllResources[i].AssignedToTeam) { if ($scope.calendarFilters.ResourceId == null || $scope.data.AllResources[i].Id == $scope.calendarFilters.ResourceId) resources.push($scope.data.AllResources[i]); } } } } return resources; }; $scope.isTakeAllDisabled = function (expCat, res) { for (var j = 0; j < expCat.Resources.length; j++) { if (expCat.Resources[j].ReadOnly) { return true; } } return false; }; $scope.hideCalendarPart = function (upper) { if (upper) $scope.calendarFilters.ShowUpper = !$scope.calendarFilters.ShowUpper; else $scope.calendarFilters.ShowLower = !$scope.calendarFilters.ShowLower; if (upper && !$scope.calendarFilters.ShowUpper) $("#showButtomMode").switcher('disable'); else $("#showButtomMode").switcher('enable'); if (!upper && !$scope.calendarFilters.ShowLower) $("#showTopMode").switcher('disable'); else $("#showTopMode").switcher('enable'); if ($scope.data != null) { for (var i = 0; i < $scope.data.Calendar.length; i++) { $scope.data.Calendar[i].IsLowerHidden = !$scope.calendarFilters.ShowLower; $scope.data.Calendar[i].IsUpperHidden = !$scope.calendarFilters.ShowUpper; } } // force digest cycle as this method could being called from JS $scope.$digest(); }; $scope.switchUOMMode = function (value) { var newValue = value != null ? value : !$scope.calendarFilters.IsUOMHours; $scope.calendarFilters.IsUOMHours = newValue; $scope.getCalendar(); }; $scope.switchGroupByTeam = function (value) { var newValue = value != null ? value : !$scope.calendarFilters.GroupByTeam; $scope.calendarFilters.GroupByTeam = newValue; $scope.getCalendar(); }; $scope.switchCapacityVew = function (value) { var newValue = value != null ? value : !$scope.calendarFilters.IsCapacityModeActuals; $scope.calendarFilters.IsCapacityModeActuals = newValue; $scope.getCalendar(); }; $scope.switchViewMode = function (value) { var newValue = value != null ? value : !$scope.calendarFilters.IsViewModeMonth; $scope.calendarFilters.IsViewModeMonth = newValue; swithViewMode(); // force digest cycle as this method could being called from JS $scope.$digest(); }; function swithViewMode() { if (!$scope.data) return; var newValue = $scope.calendarFilters.IsViewModeMonth; var j; for (j = 0; j < $scope.data.YearHeaders.length; j++) { $scope.data.YearHeaders[j].SpanCount = 0; } for (var i = 0; i < $scope.data.Headers.length; i++) { var header = $scope.data.Headers[i]; if (header.IsMonth) { header.Collapsed = newValue; header.Show = newValue; header.CollapsedClass = newValue ? $scope.CollapsedIcon : $scope.NonCollapsedIcon; for (j = 0; j < $scope.data.YearHeaders.length; j++) { if ($scope.data.YearHeaders[j].Title == header.Year) { if (newValue) { $scope.data.YearHeaders[j].SpanCount++; // -= header.Weeks.length - 1; } else { $scope.data.YearHeaders[j].SpanCount += header.Weeks.length; } //break; } } } else { header.Collapsed = newValue; header.Show = !newValue; } header.Initialized = header.Initialized || header.Show; } getVisibleCellCount(); } function getVisibleCellCount() { var count = 0; for (var i = 0; i < $scope.data.Headers.length; i++) { var header = $scope.data.Headers[i]; if (header.Show) count++; } $scope.data.VisibleCellCount = count; } $scope.switchBarMode = function () { var newValue = !$scope.calendarFilters.IsBarMode; $scope.calendarFilters.IsBarMode = newValue; if (!$scope.data) return; // update project rows CSS for (var rowIndex = 0; rowIndex < $scope.data.Calendar.length; rowIndex++) { if ($scope.data.Calendar[rowIndex].RowType == 0) for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) { updateCSSClass($scope.data.Calendar[rowIndex], null, colIndex); } } // force digest cycle as this method could being called from JS $scope.$digest(); }; $scope.changeCapacity = function (value) { $scope.calendarFilters.ShowCapacity = value; if (!$scope.data) return; for (var i = 0; i < $scope.data.Calendar.length; i++) { if ($scope.data.Calendar[i].RowType == 7) { var expCatTotal = $scope.data.Calendar[i]; refreshTotalSpreadVal(expCatTotal); } } // force digest cycle as this method could being called from JS $scope.$digest(); }; $scope.changeSortBy = function (value) { $scope.calendarFilters.sortBy = value; $scope.getCalendar(); }; $scope.switchSortOrder = function () { var newValue = !$scope.calendarFilters.sortOrder; $scope.calendarFilters.sortOrder = newValue; $scope.getCalendar(); }; $scope.onMonthHeaderClick = function (header) { header.Collapsed = !header.Collapsed; header.Show = !header.Show; header.CollapsedClass = header.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon; header.Initialized = header.Initialized || header.Show; var i; if (header.Weeks && header.Weeks.length > 0) for (i = 0; i < header.Weeks.length; i++) { $scope.data.Headers[header.Weeks[i]].Collapsed = header.Collapsed; $scope.data.Headers[header.Weeks[i]].Show = !header.Collapsed; $scope.data.Headers[header.Weeks[i]].Initialized = $scope.data.Headers[header.Weeks[i]].Initialized || $scope.data.Headers[header.Weeks[i]].Show; } for (i = 0; i < $scope.data.YearHeaders.length; i++) { if ($scope.data.YearHeaders[i].Title == header.Year) { if (header.Collapsed) { $scope.data.YearHeaders[i].SpanCount -= header.Weeks.length - 1; } else { $scope.data.YearHeaders[i].SpanCount += header.Weeks.length - 1; } break; } } getVisibleCellCount(); $scope.onResize(); }; $scope.anyUpdated = function () { return ($scope.data2Update && $scope.data2Update.ChangedExpCats && $scope.data2Update.ChangedExpCats.length > 0); }; $scope.onParentNodeClick = function (row, $event) { if ($($event.target).parents('.scenario-name').length > 0 || $($event.target).parents('.menuGroup').length > 0) return; if (row.ProjectId != null && row.ExpCatId == null) { row.ProjectCollapsed = !row.ProjectCollapsed; row.CollapsedClass = row.ProjectCollapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon; } else if (row.ExpCatId != null) { row.ExpCatCollapsed = !row.ExpCatCollapsed; if (row.ScenarioId != null) row.CollapsedClass = row.ExpCatCollapsed ? $scope.ExpCatCollapsedIcon : $scope.ExpCatNonCollapsedIcon; else row.CollapsedClass = row.ExpCatCollapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon; } //else if (row.ExpCatId == null) { // row.ScenarioCollapsed = !row.ScenarioCollapsed; // row.CollapsedClass = row.ScenarioCollapsed ? $scope.ScenarioCollapsedIcon : $scope.ScenarioNonCollapsedIcon; //} setChildrenCollapsed(row, false, row.IsParentCollapsed); //$scope.onResize(); }; $scope.CheckLock = function ($event, tableId, fieldId, url) { if (CheckLock(getEventTargetId($event), tableId, fieldId)) { // SA. ENV-905. Added backurl to navigation link var currentUrl = document.location.pathname + document.location.search; var backUrl = "backUrl=" + encodeURIComponent(currentUrl); var backName = ""; var navigateToUrl = url + '/' + fieldId + "?" + backUrl; if ($scope.pageTitle && ($scope.pageTitle.length > 0)) // SA. The title of the page to return. Used to display in scenario form button backName = "&backName=" + encodeURIComponent($scope.pageTitle); var navigateToUrl = url + '/' + fieldId + "?" + backUrl + backName; document.location.href = navigateToUrl; } }; $scope.ToggleStatus = function ($event, tableId, fieldId) { if (CheckLock(getEventTargetId($event), tableId, fieldId)) { if (fieldId == null || fieldId == "") return ""; var url = "/ForecastDashboard/CheckIfActive/"; var request = { 'scenarioId': fieldId }; $.get(url, request, function (data) { if (data == null || data == "") { $scope.ToggleStatusConfirmed(fieldId); return ''; } else { bootbox.confirm({ message: "There is an active scenario for this project already. Are you sure you want to activate this scenario instead of active one?", callback: function (result) { if (result) { $scope.ToggleStatusConfirmed(fieldId); } }, className: "bootbox-sm" }); } }); } }; $scope.ToggleStatusConfirmed = function (scenarioId) { if (scenarioId == null || scenarioId == "") return ""; var url = "/ForecastDashboard/ToggleStatus/"; var request = { 'scenarioId': scenarioId }; $.get(url, request, function (data) { $scope.getCalendar(); }); return ''; }; $scope.CalcRemainingCapacity = function (capacity, index) { //for (var i = 0; i < $scope.data.Calendar.length; i++) { // if ($scope.data.Calendar[i].IsTotals && $scope.data.Calendar[i].RowType == 5) { // $scope.grandtotalrow = $scope.data.Calendar[i]; // break; // } //} return (capacity - $scope.grandtotalrow.QuantityValues[index]); // - $scope.vacationrow.QuantityValues[index] - $scope.trainingrow.QuantityValues[index]); }; $scope.CopyScenario = function ($event, scenarioId) { if (CheckLock(getEventTargetId($event), 'Scenario', scenarioId)) { if (scenarioId == null || scenarioId == "") return ""; var url = "/Scenarios/Details/" + scenarioId + '?ptab=copy'; var backUrl = '&backUrl=' + encodeURIComponent('/CapacityManagement'); if (!!$scope.calendarFilters.TeamId) backUrl = '&backUrl=' + encodeURIComponent('/Team/Board?ptab=calendar'); else if (!!$scope.calendarFilters.ViewId) backUrl = '&backUrl=' + encodeURIComponent('/View/Board?ptab=calendar'); document.location.href = url; //+backUrl; } }; $scope.AddScenario = function ($event, projectId) { if (typeof loadScenario === 'function') loadScenario(projectId); }; function getEventTargetId($event) { if (!$event.target.id || $event.target.id === '') return $event.target.parentElement.id; return $event.target.id; } $scope.SelectedFilterElementChanged = function () { if ($scope.CalendarFilterMode.SelectedItemId && ($scope.CalendarFilterMode.SelectedItemId.length > 0)) { if ($scope.dataSection && ($scope.dataSection.length > 0)) { var prefs = collectPreferences($scope.dataSection); prefs.push({ Key: "filteredCompany", Value: $scope.CalendarFilterMode.SelectedItemId }); saveUserPagePreferences(prefs, $scope.dataSection); } } // SA. ENV-799 $scope.loadCalendarData(); // ENV-539. For some reason select2 jQuery control loose selected value just after $scope.digest() // so we need to set value again on next JS iteration. $timeout(function () { $('[name=selFilterElement]').select2("val", $scope.CalendarFilterMode.SelectedItemId); }, 0, false); } $scope.loadCalendarData = function () { // SA. ENV-799. Begin $scope.calendarFilters.CompanyId = null; $scope.calendarFilters.ViewId = null; $scope.calendarFilters.TeamId = null; $scope.calendarFilters.ResourceId = null; if ($scope.CalendarFilterMode.IsCompany) $scope.calendarFilters.CompanyId = $scope.CalendarFilterMode.SelectedItemId; if ($scope.CalendarFilterMode.IsView) $scope.calendarFilters.ViewId = $scope.CalendarFilterMode.SelectedItemId; if ($scope.CalendarFilterMode.IsTeam) $scope.calendarFilters.TeamId = $scope.CalendarFilterMode.SelectedItemId; if ($scope.CalendarFilterMode.IsResource) $scope.calendarFilters.ResourceId = $scope.CalendarFilterMode.SelectedItemId; // SA. ENV-799. End $scope.getCalendar(); } // SA. ENV-799. Begin $scope.switchCompanyFilterMode = function (preserverSelection) { if (!$scope.CalendarFilterMode.IsCompany) $scope.CalendarFilterMode.IsCompany = true; $scope.CalendarFilterMode.IsView = false; $scope.CalendarFilterMode.IsTeam = false; $scope.CalendarFilterMode.IsResource = false; $scope.CalendarFilterMode.FilteredEntityTitle = "Company"; if (($scope.availableFilterOptions != null) && ($scope.availableFilterOptions.Companies != null)) { $scope.displayedOptions = $scope.availableFilterOptions.Companies; for (var i = 0; i < $scope.displayedOptions.length; i++) { var option = $scope.displayedOptions[i]; option.CSSClass = 'ddl-level-item'; if (option.Group && option.Group.Name && option.Group.Name.length > 0) { option.CSSClass += ' pad-left'; } } } if (!preserverSelection) { $scope.CalendarFilterMode.SelectedItemId = null; $scope.$broadcast('selectedSourceChanged'); } }; $scope.switchViewFilterMode = function (preserverSelection) { if (!$scope.CalendarFilterMode.IsView) $scope.CalendarFilterMode.IsView = true; $scope.CalendarFilterMode.IsCompany = false; $scope.CalendarFilterMode.IsTeam = false; $scope.CalendarFilterMode.IsResource = false; $scope.CalendarFilterMode.FilteredEntityTitle = "View"; if (($scope.availableFilterOptions != null) && ($scope.availableFilterOptions.Views != null)) $scope.displayedOptions = $scope.availableFilterOptions.Views; if (!preserverSelection) { $scope.CalendarFilterMode.SelectedItemId = null; $scope.$broadcast('selectedSourceChanged'); } }; $scope.switchTeamFilterMode = function (preserverSelection) { if (!$scope.CalendarFilterMode.IsTeam) $scope.CalendarFilterMode.IsTeam = true; $scope.CalendarFilterMode.IsCompany = false; $scope.CalendarFilterMode.IsView = false; $scope.CalendarFilterMode.IsResource = false; $scope.CalendarFilterMode.FilteredEntityTitle = "Team"; if (($scope.availableFilterOptions != null) && ($scope.availableFilterOptions.Teams != null)) $scope.displayedOptions = $scope.availableFilterOptions.Teams; if (!preserverSelection) { $scope.CalendarFilterMode.SelectedItemId = null; $scope.$broadcast('selectedSourceChanged'); } }; $scope.switchResourceFilterMode = function (preserverSelection) { if (!$scope.CalendarFilterMode.IsResource) $scope.CalendarFilterMode.IsResource = true; $scope.CalendarFilterMode.IsCompany = false; $scope.CalendarFilterMode.IsView = false; $scope.CalendarFilterMode.IsTeam = false; $scope.CalendarFilterMode.FilteredEntityTitle = "Resource"; $scope.IsCapacityModeActuals = true; // SA. ENV-886. Individual resource calendar shows actuals only if (!preserverSelection) { $scope.CalendarFilterMode.SelectedItemId = null; $scope.$broadcast('selectedSourceChanged'); } }; $scope.scrollHeader = function (evt) { //if (flag) { // return; //} var e = evt ? evt : window.event; var t = e.target ? e.target : e.srcElement; if (t.nodeType == 3) { t = t.parentNode; } var tid = t.id.replace(':scroller', ''); var fh = ge$(tid + ':scroller:fx'); var sd = ge$(tid + ':scroller'); fh.style.left = (0 - sd.scrollLeft) + 'px'; var cf = ge$(tid + '_CFB'); if (cf) { var dmt = parseInt(cf.getAttribute('dmt')); cf.style.marginTop = (0 - (sd.scrollTop + dmt)) + 'px'; } }; function ge$(d) { return document.getElementById(d); } $scope.clearWidth = function () { $scope.monthCol = []; $scope.weekCol = []; } function checkBrowser() { var userAgent = $window.navigator.userAgent; var browsers = { chrome: /chrome/i, safari: /safari/i, firefox: /firefox/i, ie: /internet explorer/i, ie1: /trident/i }; for (var key in browsers) { if (browsers[key].test(userAgent)) { return key; } }; return 'unknown'; } $scope.onResize = function () { var headerWidth = $scope.headerWidth; if ($scope.data) { var tableHeightMin = 450; var scrollBarsWH = $.getScrollBarWidthHeight(); var browserNonIE = checkBrowser() != "ie" && checkBrowser() != "ie1";//IE places scrollbars above the content and does not need additional space for scrollbar var isAC = ($(".ac").length > 0); //resize conteiner height var noVScroll = ($(".ac-no-v-scroll").length > 0); if (noVScroll || $(".height-container table").height() < tableHeightMin) { $(".height-container").height($("#capacity-table").height() + scrollBarsWH[1]); } //resize conteiner width var vertScrollShown = $("#capacity-table").height() > $(".height-container").height(); //$(".height-container table").height() > (tableHeightMin + +scrollBarWidth); if (isAC) { $(".width-container").width(Math.min((headerWidth * $scope.data.VisibleCellCount) + (browserNonIE && vertScrollShown ? scrollBarsWH[0] : 0) + 1, $scope.containerWidth - $scope.firstColWidth)); } else { $(".width-container").width(Math.min(headerWidth * $scope.data.VisibleCellCount + (browserNonIE && vertScrollShown ? scrollBarsWH[0] : 0), $scope.containerWidth - $scope.firstColWidth - 1)); } //resize conteiner height again when horizont scroll bar appears if (noVScroll && browserNonIE) { var horizontScrollShown = $("#capacity-table").width() > $(".height-container").width(); if (horizontScrollShown) { $(".height-container").height($(".height-container").height() + scrollBarsWH[1]); } } } } }]).directive('watchResizing', function () { return { restrict: 'A', link: function (scope, elem, attr, ctrl) { elem.bind('resize', function (e) { scope.containerWidth = $("#controller1").outerWidth(); scope.firstColWidth = $("div[id*='fxcol'").width(); scope.onResize(); }); } }; }) .directive('scrollHeader', function () { return { restrict: 'A', link: function (scope, elem, attr, ctrl) { elem.bind('scroll', function (e) { scope.scrollHeader(e); }); } }; });