EnVisageOnline/Main-RMO/Source/EnVisage/Scripts/Angular/Controllers/slidersGroupController.js

632 lines
17 KiB
JavaScript

'use strict';
app.controller('slidersGroupController', ['$scope', '$http', '$location', '$timeout', function ($scope, $http, $location, $timeout) {
$scope.id = $location.absUrl().substr($location.absUrl().lastIndexOf('ls/') + 3, 36);
$scope.C_ADD_ITEMS_SELECT2_ID_TEMPLATE = "addItems_{0}";
$scope.totalAvailableSumm = 100;
$scope.slidersData = {};
$scope.arrSliders = [];
$scope.movableSliders = [];
$scope.groupId = null;
$scope.availableToAddItems = [];
$scope.isReadOnly = false;
$scope.showConfirmDialog = true;
$scope.activeSliderKey = "";
$scope.init = function (initData) {
$scope.groupId = initData.groupId;
$scope.availableToAddItems = initData.availableToAddItems;
for (var index = 0; index < initData.slidersData.length; index++) {
var key = initData.slidersData[index].DisplayId;
$scope.slidersData[key] = initData.slidersData[index];
$scope.arrSliders.push(initData.slidersData[index]);
$scope.slidersData[key].Css = ["ui-slider"];
$scope.slidersData[key].SliderContainerId = "";
}
$scope.initWatchers();
$scope.resetMovableSliders();
};
$scope.initWatchers = function () {
for (var key in $scope.slidersData) {
$scope.addSliderWatch(key);
}
}
$scope.addSliderWatch = function (key) {
var releaseWatchFunction = $scope.$watch("slidersData['" + key + "']",
function (changedSlider) {
if (key && (key.length > 0) && (key != $scope.activeSliderKey)) {
var selector = changedSlider.SliderContainerId;
$(selector).slider("value", changedSlider.AllocatePercentage);
}
}, true);
$scope.slidersData[key].unwatch = releaseWatchFunction;
}
$scope.addItemToIndexedArray = function (key) {
$scope.arrSliders.push($scope.slidersData[key]);
}
$scope.removeItemFromIndexedArray = function (dataElement) {
var index = $scope.arrSliders.indexOf(dataElement);
if (index >= 0) {
$scope.arrSliders.splice(index, 1);
}
}
$scope.recreateSliders = function () {
for (var key in $scope.slidersData) {
if ($scope.slidersData[key].IsExcludable) {
var containerSelector = $scope.slidersData[key].SliderContainerId;
var containerElement = $(containerSelector);
$scope.createSliderControl(containerElement, $scope, $scope.slidersData[key]);
}
}
}
$scope.IsEmpty = function (value) {
return !value || (value == null) || (value == "");
}
$scope.getSliderKey = function (container) {
return $(container).attr("data-slider-key");
}
$scope.setSliderValue = function (key, value) {
$scope.slidersData[key].AllocatePercentage = value;
}
$scope.resetMovableSliders = function () {
$scope.movableSliders = [];
for (var key in $scope.slidersData) {
$scope.movableSliders.push(key);
var index = $scope.slidersData[key].Css.indexOf("ui-slider-success");
if (index >= 0) {
$scope.slidersData[key].Css.splice(index, 1);
}
}
}
$scope.isSliderMovable = function (key) {
return $.inArray(key, $scope.movableSliders);
}
$scope.freezeSlider = function (key) {
var foundIndex = $scope.isSliderMovable(key);
if (foundIndex >= 0) {
$scope.slidersData[key].Css.push("ui-slider-success");
$scope.movableSliders.splice(foundIndex, 1);
}
}
$scope.disableSliders = function (excludeKey) {
for (var key in $scope.slidersData) {
if (!excludeKey || (excludeKey.length < 1) || (excludeKey != key)) {
var selector = $scope.slidersData[key].SliderContainerId;
$(selector).slider("disable");
}
}
}
$scope.enableSliders = function () {
for (var key in $scope.slidersData) {
var selector = $scope.slidersData[key].SliderContainerId;
$(selector).slider("enable");
}
}
$scope.getAllSlidersTotal = function (excludeActiveSlider) {
var total = 0;
for (var key in $scope.slidersData) {
if (!excludeActiveSlider || !$scope.activeSliderKey || ($scope.activeSliderKey.length < 1) ||
($scope.activeSliderKey != key)) {
total += $scope.slidersData[key].AllocatePercentage;
}
}
return total;
}
$scope.getMovableSlidersTotal = function (excludeActiveSlider) {
var total = 0;
$scope.movableSliders.forEach(function (key, i) {
if (!excludeActiveSlider || !$scope.activeSliderKey || ($scope.activeSliderKey.length < 1) ||
($scope.activeSliderKey != key)) {
total += $scope.slidersData[key].AllocatePercentage;
}
});
return total;
}
$scope.getUnmovableSlidersTotal = function (excludeActiveSlider) {
var total = 0;
for (var key in $scope.slidersData) {
if (!excludeActiveSlider || !$scope.activeSliderKey || ($scope.activeSliderKey.length < 1) ||
($scope.activeSliderKey != key)) {
if ($scope.movableSliders.indexOf(key) < 0) {
total += $scope.slidersData[key].AllocatePercentage;
}
}
}
return total;
}
$scope.getSlidersCount = function () {
var count = Object.keys($scope.slidersData).length;
return count;
}
$scope.onSliderSlide = function (event, ui) {
var key = $scope.getSliderKey(event.target);
if (!$scope.activeSliderKey || ($scope.activeSliderKey.length < 1) || (key != $scope.activeSliderKey))
return;
var value = Math.round(parseInt(ui.value));
$scope.setSliderValue(key, value);
$scope.recalculateDependentSliders();
};
$scope.onSliderStartSliding = function (event, ui) {
$scope.activeSliderKey = $scope.getSliderKey(event.target);
$scope.showConfirmDialog = false;
$scope.freezeSlider($scope.activeSliderKey);
if (typeof onScenarioDataChanged === 'function')
onScenarioDataChanged();
};
$scope.onSliderStopSliding = function (event, ui) {
if ($scope.showConfirmDialog) {
// Some values of the sliders group are wrong (not 100% summary).
var result = confirm("By moving this slider, you will adjust previously set values for other teams on this scenario.");
$scope.$apply(function () {
$scope.processConfirmed(result);
});
}
else {
// Fix incorrect sliders summ
$scope.correctSlidersByTotal();
}
$scope.activeSliderKey = "";
};
$scope.processConfirmed = function (result) {
var total = $scope.getAllSlidersTotal(true);
var valueToSet = $scope.totalAvailableSumm - total;
var activeKey = $scope.activeSliderKey;
$scope.activeSliderKey = "";
$scope.setSliderValue(activeKey, valueToSet);
if (result) {
$scope.resetMovableSliders();
$scope.enableSliders();
}
else {
$scope.disableSliders(activeKey);
}
}
$scope.getDistribution = function (valueToDistribute) {
// Check, can we distribute it?
var slidersCapacity = 0;
var distribution = {};
var structForSort = [];
$scope.movableSliders.forEach(function (key, i) {
var currentValue = $scope.slidersData[key].AllocatePercentage;
var currentCapacity;
if (valueToDistribute > 0)
currentCapacity = $scope.totalAvailableSumm - currentValue;
else
currentCapacity = currentValue;
slidersCapacity += currentCapacity;
if (currentCapacity != 0)
structForSort.push({ key: key, value: currentCapacity });
});
if (Math.abs(valueToDistribute) > slidersCapacity)
// We cant distribute the value, so the slider group remains correct
return null;
var sortedKeys = [];
while (structForSort.length > 0) {
var foundIndex = -1;
var minValue = $scope.totalAvailableSumm;
for (var index = 0; index < structForSort.length; index++) {
if ((foundIndex < 0) || (structForSort[index].value <= minValue)) {
foundIndex = index;
minValue = structForSort[index].value;
}
}
if (foundIndex >= 0) {
sortedKeys.push(structForSort[foundIndex].key);
structForSort.splice(foundIndex, 1);
}
else
break;
}
// Calculate the distribution map
var slidersCount = sortedKeys.length;
var remainingSumm = valueToDistribute;
for (var index = slidersCount - 1; index >= 0; index--) {
var idealPortion = remainingSumm / (index + 1);
var key = sortedKeys[index];
var currentValue = $scope.slidersData[key].AllocatePercentage;
var newCurrentSliderValue = currentValue + idealPortion;
if ((newCurrentSliderValue < 0) || (newCurrentSliderValue > $scope.totalAvailableSumm)) {
if (valueToDistribute > 0) {
distribution[key] = $scope.totalAvailableSumm - currentValue;
}
else {
distribution[key] = -currentValue;
}
remainingSumm -= distribution[key];
}
else {
if (index > 0) {
distribution[key] = idealPortion;
remainingSumm -= distribution[key];
}
else {
// The last slider
distribution[key] = remainingSumm;
}
}
}
return distribution;
}
$scope.recalculateDependentSliders = function () {
var total = 0;
var changeToDistribute = 0;
var activeSliderValue = $scope.slidersData[$scope.activeSliderKey].AllocatePercentage;
var slidersCount = $scope.getSlidersCount();
if ((slidersCount > 1) && ($scope.movableSliders.length == 0)) {
$scope.showConfirmDialog = true;
}
if (!$scope.showConfirmDialog) {
total = $scope.getAllSlidersTotal(false);
changeToDistribute = $scope.totalAvailableSumm - total;
if (changeToDistribute != 0) {
var distributionMap = $scope.getDistribution(changeToDistribute);
if (distributionMap != null) {
for (var key in distributionMap) {
var newSliderValueRaw = $scope.slidersData[key].AllocatePercentage + distributionMap[key];
var newSliderValueRounded = Math.round(newSliderValueRaw);
$scope.setSliderValue(key, newSliderValueRounded);
}
}
else
$scope.showConfirmDialog = true;
}
}
}
$scope.correctSlidersByTotal = function () {
var totalSumm = $scope.getAllSlidersTotal(false);
if (totalSumm != $scope.totalAvailableSumm) { // 100%
var unmovableSumm = $scope.getUnmovableSlidersTotal(false);
var factMovableSumm = $scope.getMovableSlidersTotal(false);
var plannedMovableSumm = $scope.totalAvailableSumm - unmovableSumm;
var popravka = plannedMovableSumm - factMovableSumm;
for (var index = $scope.movableSliders.length - 1; index >= 0; index--) {
var key = $scope.movableSliders[index];
var potentialValue = $scope.slidersData[key].AllocatePercentage + popravka;
if ((potentialValue >= 0) && (potentialValue <= 100)) {
$timeout(function () {
$scope.slidersData[key].AllocatePercentage = potentialValue;
$scope.setSliderValue(key, potentialValue);
}, 100);
break;
}
}
}
}
/* --- items in the group management --- */
$scope.showAddItemsDiv = false;
$scope.getAddItemsControlSelector = function () {
return ("#" + $scope.C_ADD_ITEMS_SELECT2_ID_TEMPLATE.replace("{0}", $scope.groupId));
}
$scope.showControlsToAddItems = function () {
$scope.showAddItemsDiv = true;
}
$scope.hideControlsToAddItems = function () {
$scope.showAddItemsDiv = false;
// Clear select2 selection
var selector = $scope.getAddItemsControlSelector();
$(selector).select2('val', '');
$scope.selectedTeams = null;
}
$scope.removeItem = function (key) {
var sliderValue = $scope.slidersData[key].AllocatePercentage;
if (sliderValue > 0) {
alert("It is not allowed to delete a team with non-zero allocation");
return;
}
if ($scope.slidersData[key].unwatch && ($scope.slidersData[key].unwatch != null))
// remove watch
$scope.slidersData[key].unwatch();
$scope.removeItemFromIndexedArray($scope.slidersData[key]);
$scope.slidersData[key] = undefined;
delete $scope.slidersData[key];
$timeout(function() {
$scope.recreateSliders();
$scope.resetMovableSliders();
$scope.enableSliders();
}, 200);
if (typeof onScenarioDataChanged === 'function')
onScenarioDataChanged();
};
// SA. ENV-1149. Shows given allocation on sliders
$scope.setAllocation = function (items) {
var externalSumm = 0;
var multiplier = 1;
// Calculate the total summ for items allocation
for (var index = 0; index < items.length; index++) {
var currentTeam = items[index];
if (currentTeam.Allocation && $.isNumeric(currentTeam.Allocation)) {
var foundSliderForTeam = $scope.getSliderByEntityId(currentTeam.TeamId);
if (foundSliderForTeam && (foundSliderForTeam != null)) {
externalSumm += currentTeam.Allocation;
}
}
}
// Set new allocation, so the total summ should be 100%
if (externalSumm > 0) {
multiplier = $scope.totalAvailableSumm / externalSumm;
for (var index = 0; index < items.length; index++) {
var currentTeam = items[index];
if (currentTeam.Allocation && $.isNumeric(currentTeam.Allocation)) {
var foundSliderForTeam = $scope.getSliderByEntityId(currentTeam.TeamId);
if (foundSliderForTeam && (foundSliderForTeam != null)) {
var newValue = Math.round(currentTeam.Allocation * multiplier);
newValue = newValue > $scope.totalAvailableSumm ? $scope.totalAvailableSumm : newValue;
$scope.setSliderValue(foundSliderForTeam.DisplayId, newValue);
}
}
}
// Correct slider values for case, the total summ is not exact 100%
$scope.correctSlidersByTotal();
}
}
// SA. ENV-1149. Shows given allocation on sliders
$scope.setReadonly = function () {
$scope.disableSliders();
$scope.isReadOnly = true;
}
$scope.addItems = function (items) {
if (!items || (items == null) || (items.length < 1)) {
// No teams selected
return;
}
var itemsToAdd = [];
for (var index = 0; index < items.length; index++) {
var currentTeam = items[index];
var foundSliderForTeam = $scope.getSliderByEntityId(currentTeam.TeamId);
if (!foundSliderForTeam || (foundSliderForTeam == null)) {
var itemName = $scope.getItemNameById(currentTeam.TeamId);
var newItemStruct = {
Text: itemName,
Value: currentTeam.TeamId
};
itemsToAdd.push(newItemStruct);
}
}
if (itemsToAdd.length > 0) {
$scope.addItemsInternal(itemsToAdd);
}
}
$scope.addItemsByUI = function() {
if (!$scope.selectedTeams || ($scope.selectedTeams == null) || ($scope.selectedTeams.length < 1)) {
// No teams selected
return;
}
$scope.addItemsInternal($scope.selectedTeams, $scope.hideControlsToAddItems);
$scope.hideControlsToAddItems();
if (typeof onScenarioDataChanged === 'function')
onScenarioDataChanged();
};
$scope.addItemsInternal = function (itemsToAdd, callBackFunction) {
$scope.registerAddedSliders(itemsToAdd);
if (callBackFunction && (typeof callBackFunction === 'function')) {
callBackFunction();
}
};
$scope.registerAddedSliders = function (selectedItems) {
var addedKeys = [];
for (var index = 0; index < selectedItems.length; index++) {
var itemId = selectedItems[index].Value;
var key = $scope.getKeyByEntityId(itemId);
$scope.slidersData[key] = {
Id: itemId,
Name: selectedItems[index].Text,
EntityId: itemId,
AllocatePercentage: 0,
IsExcludable: true,
ParentId: $scope.groupId,
DisplayId: key,
Css: ["ui-slider"]
};
addedKeys.push(key);
$scope.addItemToIndexedArray(key);
}
for (var index = 0; index < addedKeys.length; index++) {
var key = addedKeys[index];
$scope.addSliderWatch(key);
}
$scope.resetMovableSliders();
$scope.enableSliders();
}
$scope.itemIsNotSelected = function (itemId) {
return false;
}
$scope.getTeamList = function () {
var result = [];
for (var key in $scope.slidersData) {
if ($scope.slidersData[key].EntityId)
result.push($scope.slidersData[key].EntityId);
}
return result;
}
$scope.getSliderByEntityId = function (entityId) {
var result = null;
for (var key in $scope.slidersData) {
var currentId = $scope.slidersData[key].EntityId;
if (currentId && (currentId == entityId)) {
result = $scope.slidersData[key];
break;
}
}
return result;
}
$scope.getItemNameById = function (entityId) {
var name = '';
for (var index = 0; index < $scope.availableToAddItems.length; index++) {
if ($scope.availableToAddItems[index].Value == entityId) {
name = $scope.availableToAddItems[index].Text;
break;
}
}
return name;
}
$scope.getKeyByEntityId = function (entityId) {
var matchTemplate = /-/gi;
var key = entityId.replace(matchTemplate, "");
return key;
};
$scope.createSliderControl = function (jqElement, scope, dataElement) {
jqElement.slider({
range: 'min',
min: 0,
max: 100,
step: 1,
value: dataElement.AllocatePercentage,
slide: function (event, ui) {
scope.$apply(function () {
scope.onSliderSlide(event, ui);
});
},
start: scope.onSliderStartSliding,
stop: scope.onSliderStopSliding
});
};
}])
.directive('sliderKey', function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.createSliderControl($(element), scope, scope.slidersData[attrs.sliderKey]);
scope.slidersData[attrs.sliderKey].SliderContainerId = ("#" + attrs.id);
}
};
})
.filter('excludeFrom', function () {
return function (inputArray, filterCriteria) {
if (null === inputArray || undefined === inputArray)
return null;
return inputArray.filter(function (item) {
// if the value of filterCriteria is "falsy", retain the inputArray as it is
// then check if the currently checked item in the inputArray is different from the filterCriteria,
// if so, keep it in the filtered results
var exists = false;
if (filterCriteria) {
for (var key in filterCriteria) {
if (filterCriteria[key].EntityId === item.Value) {
exists = true;
break;
}
}
}
return !filterCriteria || !exists;
});
};
});