977 lines
55 KiB
JavaScript
977 lines
55 KiB
JavaScript
"use strict";
|
|
// jscs:disable validateIndentation
|
|
(function () {
|
|
'use strict';
|
|
$.widget('ui.numericSpinner', $.ui.spinner, {
|
|
_format: function (value) {
|
|
return value.toFixed(this._precision());
|
|
}
|
|
});
|
|
angular.module('myitsmApp')
|
|
.factory('customFieldLinkFunction', ['events', function (events) {
|
|
return function (scope) {
|
|
scope.showMeridian = window.showMeridian;
|
|
scope.onFieldValueChange = function (field) {
|
|
field = field || scope.data;
|
|
// this is result of user interaction, so field wil always have value
|
|
field.hasValue = true;
|
|
scope.$parent.$emit(events.FIELD_VALUE_CHANGE, field);
|
|
};
|
|
};
|
|
}])
|
|
.filter('customFieldLabelI18n', ['screenConfigurationModel', function (screenConfigurationModel) {
|
|
return function (data, ticketType) {
|
|
var classId;
|
|
if (data.extension && data.extension.length > 0 && data.extension[0].classId) {
|
|
classId = data.extension[0].classId;
|
|
}
|
|
var localizedField = screenConfigurationModel.getLocalizedFieldByNameForTicketType(data.name, ticketType, classId);
|
|
return (localizedField && localizedField.label) ? localizedField.label : data.label;
|
|
};
|
|
}])
|
|
.directive('customFieldLabel', function () {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
template: '<label ux-id="field-label" id="{{data.name + \'Label\'}}" class="label__text label_control-wrap" ng-class="{\'required__label\': data.isRequired && ($parent.$parent.editMode || $parent.$parent.$parent.editMode)}" data-required="{{\'common.label.required.bracketed\' | i18n}}" ng-hide="hideLabel()" aria-label="{{ data | customFieldLabelI18n: typeOfTicket }}" title="{{ data | customFieldLabelI18n: typeOfTicket }}" for="{{data.name + \'InputBox\'}}">{{ data | customFieldLabelI18n: typeOfTicket }}</label>',
|
|
link: function (scope) {
|
|
//scope leaks so careful of setting anything here
|
|
scope.typeOfTicket = scope.context ? (scope.context.type || scope.context.ticketType) : '';
|
|
scope.hideLabel = function () {
|
|
var isDataPresent;
|
|
if (scope.alwaysShowLabel) {
|
|
return false;
|
|
}
|
|
isDataPresent = scope.data.ootb || !!scope.data.value || scope.data.value === 0;
|
|
return scope.isHideLabel && (!scope.$parent.$parent.editMode || !(scope.$parent.$parent.$parent && scope.$parent.$parent.$parent.editMode)) ? scope.isHideLabel : !((!scope.data.hideLabel && isDataPresent) || scope.$parent.$parent.editMode || (scope.$parent.$parent.$parent && scope.$parent.$parent.$parent.editMode));
|
|
};
|
|
}
|
|
};
|
|
})
|
|
.directive('characterCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
charLimit: '=',
|
|
isHideLabel: '=',
|
|
typeOfTicket: '=?'
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/character-custom-field.html',
|
|
link: function (scope, element) {
|
|
customFieldLinkFunction(scope);
|
|
scope.status = {
|
|
isCollapsed: true
|
|
};
|
|
//The logic of generating Id for other ticket types is different than that of Task. Task uses Field Id 1 as its
|
|
//primary Ticket Id. The input char length is returned as 1, but the task ID is more than 1 char so, UC shows the
|
|
//maximum characters reached message always.The below fix is to set the field maxLength to 15.
|
|
if (scope.data.label === 'Task ID') {
|
|
scope.data.maxLength = 15;
|
|
}
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value && value !== '#$#') {
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
if (scope.data.maxLength > 0) {
|
|
element.find('.form-control').attr('maxlength', scope.data.maxLength);
|
|
}
|
|
var originaldata = _.cloneDeep(scope.data.value);
|
|
scope.$on(events.SAVE_CHANGES, function () {
|
|
originaldata = _.cloneDeep(scope.data.value);
|
|
});
|
|
scope.$on(events.DISCARD_CHANGES, function () {
|
|
scope.data.value = _.cloneDeep(originaldata);
|
|
});
|
|
}
|
|
};
|
|
}])
|
|
.directive('textareaCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '=',
|
|
charLimit: '=?',
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/textarea-custom-field.html',
|
|
link: function (scope, element) {
|
|
customFieldLinkFunction(scope);
|
|
scope.status = {
|
|
isCollapsed: true
|
|
};
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value && value !== '#$#') {
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
if (scope.data.maxLength > 0) {
|
|
element.find('.form-control').attr('maxlength', scope.data.maxLength);
|
|
}
|
|
var originaldata = _.cloneDeep(scope.data.value);
|
|
scope.$on(events.SAVE_CHANGES, function () {
|
|
originaldata = _.cloneDeep(scope.data.value);
|
|
});
|
|
scope.$on(events.DISCARD_CHANGES, function () {
|
|
scope.data.value = _.cloneDeep(originaldata);
|
|
});
|
|
}
|
|
};
|
|
}])
|
|
.directive('staticSelectionCustomField', ['customFieldLinkFunction', 'screenConfigurationModel', 'events', '$filter', '$rootScope',
|
|
function (customFieldLinkFunction, screenConfigurationModel, events, $filter, $rootScope) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
context: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '='
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/static-selection-custom-field.html',
|
|
link: function (scope) {
|
|
customFieldLinkFunction(scope);
|
|
var field = scope.data;
|
|
var fieldLabels = screenConfigurationModel.fieldLabels || [];
|
|
var dropdownLabels;
|
|
scope.dropdownOptions = {
|
|
selectedOption: null
|
|
};
|
|
if (EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION.indexOf(scope.context.type) !== -1) {
|
|
dropdownLabels = {
|
|
options: field.options
|
|
};
|
|
}
|
|
else {
|
|
dropdownLabels = _.find(fieldLabels, function (fieldItem) {
|
|
var validField = fieldItem.name === scope.data.name;
|
|
if (validField && scope.context && scope.context.ticketType === EntityVO.TYPE_ASSET) {
|
|
if (fieldItem.classIds && fieldItem.classIds.length) {
|
|
validField = fieldItem.classIds[0] === 'ITSM AssetBase' || fieldItem.classIds[0] === scope.context.classId;
|
|
}
|
|
}
|
|
return validField;
|
|
});
|
|
}
|
|
var dynamicSelectionOptions = [
|
|
{ index: 0, value: 0, label: $filter('i18n')('customField.selection.label.yes') },
|
|
{ index: 1, value: 1, label: $filter('i18n')('customField.selection.label.no') }
|
|
];
|
|
scope.handleRadioEnterKey = function (option) {
|
|
if (!scope.data.isReadOnly && scope.isEditable) {
|
|
scope.selectItem(option);
|
|
if (!scope.data.radioFieldVal) {
|
|
scope.data.radioFieldVal = !scope.data.radioFieldVal;
|
|
}
|
|
;
|
|
}
|
|
};
|
|
scope.options = (field.isSelectionField()) ? dynamicSelectionOptions : (dropdownLabels && dropdownLabels.options || []);
|
|
scope.selectItem = function (option) {
|
|
scope.dropdownOptions.selectedOption = option;
|
|
if (!_.isEmpty(option)) {
|
|
if (field.isRadioField() && option.index === field.getValue()) {
|
|
scope.dropdownOptions.selectedOption = null;
|
|
scope.data.radioFieldVal = null;
|
|
field.clearValue();
|
|
}
|
|
else {
|
|
field.setValue(option.name ? option.name : option.value);
|
|
}
|
|
}
|
|
else {
|
|
field.clearValue();
|
|
}
|
|
scope.onFieldValueChange();
|
|
};
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value !== '#$#') {
|
|
refreshValue();
|
|
scope.onFieldValueChange();
|
|
field.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
var unbindRootScopeListener = $rootScope.$on(events.TICKET_TEMPLATE_UPDATED, function (events, data) {
|
|
if (scope.data.name === 'serviceType' && data) {
|
|
if (data.selectedServiceType && data.selectedServiceType.name) {
|
|
var option = _.find(scope.options, { name: data.selectedServiceType.name });
|
|
if (option) {
|
|
scope.selectItem(option);
|
|
}
|
|
}
|
|
else {
|
|
scope.selectItem(null);
|
|
}
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
scope.$on(events.RISK_LEVEL_CHANGE, function (events, field) {
|
|
if (scope.data.name === "changeReason") {
|
|
if (angular.isUndefined(scope.data.originalRequired) || scope.data.originalRequired === null) {
|
|
scope.data.originalRequired = scope.data.isRequired;
|
|
}
|
|
scope.data.isRequired = scope.data.originalRequired || field.isRequired;
|
|
}
|
|
});
|
|
function refreshValue() {
|
|
var selectedValueIndex = scope.data.getValue();
|
|
if (selectedValueIndex && (typeof selectedValueIndex === 'object')) {
|
|
selectedValueIndex = selectedValueIndex.name;
|
|
}
|
|
scope.data.radioFieldVal = scope.data.value;
|
|
if (angular.isDefined(selectedValueIndex) && selectedValueIndex !== null) {
|
|
if (scope.data.ootb) {
|
|
scope.dropdownOptions.selectedOption = _.find(scope.options, { name: selectedValueIndex });
|
|
if (!scope.dropdownOptions.selectedOption) { // Fix for SW00538722
|
|
scope.dropdownOptions.selectedOption = _.find(scope.options, { index: selectedValueIndex });
|
|
}
|
|
}
|
|
else {
|
|
scope.dropdownOptions.selectedOption = _.find(scope.options, function (option) {
|
|
return option.index === selectedValueIndex || option.name === selectedValueIndex;
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
scope.dropdownOptions.selectedOption = null;
|
|
}
|
|
}
|
|
refreshValue();
|
|
scope.$on(events.REFRESH_FIELD_VALUES, refreshValue);
|
|
scope.$on('$destroy', function () {
|
|
unbindRootScopeListener();
|
|
});
|
|
}
|
|
};
|
|
}])
|
|
.directive('checkboxCustomField', ['customFieldLinkFunction', 'screenConfigurationModel', '$filter', 'events',
|
|
function (customFieldLinkFunction, screenConfigurationModel, $filter, events) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '=',
|
|
typeOfTicket: '=?'
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/checkbox-custom-field.html',
|
|
link: function (scope) {
|
|
customFieldLinkFunction(scope);
|
|
//value of checkbox ngModel should be true or false for required validation to work.
|
|
scope.checkbox = {
|
|
value: scope.data.value !== -1 && scope.data.value !== undefined && scope.data.value !== null
|
|
};
|
|
var field = scope.data, oldFieldData = angular.copy(scope.data);
|
|
var fieldLabels = screenConfigurationModel.fieldLabels || [];
|
|
var checkboxLabels = _.find(fieldLabels, { name: field.name }) || field;
|
|
var cbDynamicOption = getCbDynamicOption(field.value);
|
|
scope.editLabel = (checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0].label : '';
|
|
if (field.isSelectionField()) {
|
|
scope.cbOption = cbDynamicOption;
|
|
if (field.dynamicField) {
|
|
scope.alwaysShowLabel = true;
|
|
}
|
|
}
|
|
else {
|
|
scope.cbOption = (checkboxLabels && checkboxLabels.options) ? checkboxLabels.options[0] : { index: -1, label: '-' };
|
|
if (checkboxLabels && checkboxLabels.options && field.value !== checkboxLabels.options[0].index) {
|
|
field.setValue(-1);
|
|
scope.cbOption = { index: -1, label: '-' };
|
|
}
|
|
}
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value !== '#$#') {
|
|
if (!field.isSelectionField()) {
|
|
if (value !== -1) {
|
|
field.setValue(-1);
|
|
}
|
|
else {
|
|
field.setValue((checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0].index : 0);
|
|
}
|
|
}
|
|
else {
|
|
scope.cbOption = getCbDynamicOption(value);
|
|
if (value) {
|
|
field.clearValue();
|
|
}
|
|
}
|
|
scope.selectItem();
|
|
field.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
scope.selectItem = function () {
|
|
if (!field.isSelectionField()) {
|
|
if (!(field.value === -1 || field.value === null || field.value === undefined)) {
|
|
field.setValue(-1);
|
|
scope.cbOption = { index: -1, label: '-' };
|
|
}
|
|
else {
|
|
scope.cbOption = (checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0] : { index: 0, label: '' };
|
|
field.setValue((checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0].index : 0);
|
|
}
|
|
}
|
|
else {
|
|
if (field.value !== null && field.value !== '' && field.value !== undefined) {
|
|
field.clearValue();
|
|
}
|
|
else {
|
|
field.setValue(scope.cbOption.index);
|
|
}
|
|
scope.cbOption = getCbDynamicOption(field.value);
|
|
}
|
|
scope.onFieldValueChange();
|
|
};
|
|
function getCbDynamicOption(value) {
|
|
return (value === null) ?
|
|
{ index: 0, label: $filter('i18n')('customField.checkbox.label.off') } :
|
|
{ index: 0, label: $filter('i18n')('customField.checkbox.label.on') };
|
|
}
|
|
function handleDiscardChanges() {
|
|
var oldVal = oldFieldData.getValue();
|
|
if (field.isSelectionField()) {
|
|
if (oldVal === null || oldVal === '' || oldVal === undefined) {
|
|
field.clearValue();
|
|
}
|
|
else {
|
|
field.setValue(scope.cbOption.index);
|
|
}
|
|
scope.cbOption = getCbDynamicOption(field.value);
|
|
}
|
|
else {
|
|
if (oldVal === -1 || oldVal === null || oldVal === undefined) {
|
|
field.setValue(-1);
|
|
scope.cbOption = { index: -1, label: '-' };
|
|
}
|
|
else {
|
|
scope.cbOption = (checkboxLabels && checkboxLabels.options && checkboxLabels.options.length) ? checkboxLabels.options[0] : { index: 0, label: '' };
|
|
field.setValue(oldVal);
|
|
}
|
|
}
|
|
}
|
|
function updateOldDataField() {
|
|
oldFieldData = angular.copy(scope.data);
|
|
}
|
|
scope.$on(events.RESET_DYNAMIC_FIELDS, handleDiscardChanges);
|
|
scope.$on(events.UPDATE_DYNAMIC_DATA, updateOldDataField);
|
|
}
|
|
};
|
|
}])
|
|
.directive('numberCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '=',
|
|
typeOfTicket: '=?'
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/number-custom-field.html',
|
|
link: function (scope) {
|
|
scope.data.step = Math.pow(10, -scope.data.precision);
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value !== '#$#') {
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
customFieldLinkFunction(scope);
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
var originaldata = _.cloneDeep(scope.data.value);
|
|
scope.$on(events.SAVE_CHANGES, function () {
|
|
originaldata = _.cloneDeep(scope.data.value);
|
|
});
|
|
scope.$on(events.DISCARD_CHANGES, function () {
|
|
scope.data.value = _.cloneDeep(originaldata);
|
|
});
|
|
}
|
|
};
|
|
}])
|
|
.directive('dateTimeCustomField', ['customFieldLinkFunction', '$filter', 'events', 'configurationModel', function (customFieldLinkFunction, $filter, events, configurationModel) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '=',
|
|
typeOfTicket: '=?'
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/datetime-custom-field.html',
|
|
link: function (scope) {
|
|
customFieldLinkFunction(scope);
|
|
scope.status = {
|
|
opened: false
|
|
};
|
|
scope.datePickerOptions = {
|
|
startingDay: configurationModel.getWeekStartingDay(),
|
|
'show-weeks': false,
|
|
minDate: moment().year(1970).month(0).date(2),
|
|
maxDate: moment().year(2038).month(0).date(18)
|
|
};
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value && value !== '#$#') {
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
scope.open = function ($event) {
|
|
$event.preventDefault();
|
|
$event.stopPropagation();
|
|
scope.status.opened = true;
|
|
};
|
|
var originaldata = _.cloneDeep(scope.data.value);
|
|
scope.$on(events.SAVE_CHANGES, function () {
|
|
originaldata = _.cloneDeep(scope.data.value);
|
|
});
|
|
scope.$on(events.DISCARD_CHANGES, function () {
|
|
scope.data.value = _.cloneDeep(originaldata);
|
|
});
|
|
}
|
|
};
|
|
}])
|
|
.directive('dateCustomField', ['customFieldLinkFunction', '$filter', 'configurationModel', function (customFieldLinkFunction, $filter, configurationModel) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '='
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/date-custom-field.html',
|
|
link: function (scope) {
|
|
customFieldLinkFunction(scope);
|
|
scope.status = {
|
|
opened: false
|
|
};
|
|
scope.datePickerOptions = {
|
|
startingDay: configurationModel.getWeekStartingDay(),
|
|
'show-weeks': false,
|
|
minDate: moment().year(1970).month(0).date(2)
|
|
};
|
|
if (!scope.data.isDateTimeField()) {
|
|
if (scope.data.value) {
|
|
/* We are using the date filter in date-custom-field template and the date filter converts the epoch value according to the current timezone. We need to display date values in GMT.
|
|
The getTimezoneOffset () method returns the time difference between UTC time and local time in minutes. Adding timezone offset as it is being removed by the date filter */
|
|
var gmtDate = new Date(scope.data.value);
|
|
var fieldValue = gmtDate.valueOf() + (gmtDate.getTimezoneOffset() * 60000);
|
|
if (fieldValue) {
|
|
scope.data.value = fieldValue;
|
|
}
|
|
}
|
|
}
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value && value !== '#$#') {
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
scope.open = function ($event) {
|
|
$event.preventDefault();
|
|
$event.stopPropagation();
|
|
scope.status.opened = true;
|
|
};
|
|
}
|
|
};
|
|
}])
|
|
.directive('timeCustomField', ['customFieldLinkFunction', '$filter', 'events', function (customFieldLinkFunction, $filter, events) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
isEditable: '=',
|
|
isHideLabel: '='
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/time-custom-field.html',
|
|
link: function (scope) {
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value && value !== '#$#') {
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
customFieldLinkFunction(scope);
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
var originaldata = _.cloneDeep(scope.data.value);
|
|
scope.$on(events.SAVE_CHANGES, function () {
|
|
originaldata = _.cloneDeep(scope.data.value);
|
|
});
|
|
scope.$on(events.DISCARD_CHANGES, function () {
|
|
scope.data.value = _.cloneDeep(originaldata);
|
|
});
|
|
}
|
|
};
|
|
}])
|
|
.directive('validNumber', ['$timeout', function ($timeout) {
|
|
return {
|
|
restrict: 'A',
|
|
require: 'ngModel',
|
|
link: function (scope, elem, attr, ctrl) {
|
|
ctrl.$parsers.push(checkPrecision, checkRequired);
|
|
function checkPrecision(val) {
|
|
var stringVal = val ? val.toString() : '';
|
|
// do nothing if we got an invalid number or smth like '123' or '123.'
|
|
if (!stringVal || stringVal.indexOf('.') === -1 || !stringVal.split('.')[1].length) {
|
|
return val;
|
|
}
|
|
var precision = parseInt(attr.precision);
|
|
var precisionLen = stringVal.split('.')[1].length;
|
|
var valid = true;
|
|
var newVal = val;
|
|
var sliceAmount = 0;
|
|
var parseVal = '';
|
|
if (!precision) {
|
|
// precision=0 but we got 123.4
|
|
valid = false;
|
|
sliceAmount = precisionLen + 1; // +1 means to cut decimal separator '.' as well
|
|
}
|
|
else if (precision < precisionLen) {
|
|
// precision=2 but we got 123.456
|
|
valid = false;
|
|
sliceAmount = precisionLen - attr.precision;
|
|
}
|
|
if (!valid) {
|
|
newVal = parseFloat(stringVal.slice(0, 0 - sliceAmount)); // slice last sliceAmount digits
|
|
parseVal = stringVal.slice(0, 0 - sliceAmount);
|
|
$timeout(function () {
|
|
ctrl.$setViewValue(attr.numberType === 'integer' ? parseInt(parseVal) : parseFloat(parseVal));
|
|
ctrl.$render();
|
|
}, 0);
|
|
}
|
|
return newVal;
|
|
}
|
|
function checkRequired(val) {
|
|
if (JSON.parse(attr.numberRequired)) {
|
|
if (ctrl.$isEmpty(val)) {
|
|
ctrl.$setValidity('required', false);
|
|
}
|
|
else if (!isNaN(val)) {
|
|
ctrl.$setValidity('required', true);
|
|
return val;
|
|
}
|
|
}
|
|
else {
|
|
ctrl.$setValidity('required', true);
|
|
return val;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}])
|
|
.directive('numberInput', ['i18nService', function (i18nService) {
|
|
return {
|
|
restrict: 'A',
|
|
require: 'ngModel',
|
|
scope: {
|
|
min: '@',
|
|
max: '@',
|
|
precision: '@',
|
|
numberType: '@'
|
|
},
|
|
link: function (scope, element, attrs, ctrl) {
|
|
var min = parseFloat(attrs.min);
|
|
var max = parseFloat(attrs.max);
|
|
var precision = parseInt(attrs.precision);
|
|
if (isNaN(precision)) {
|
|
precision = 0;
|
|
}
|
|
var step = Math.pow(10, -precision);
|
|
var numberType = attrs.numberType;
|
|
element.numericSpinner({
|
|
step: step,
|
|
spin: function (event, ui) {
|
|
var newValue = ui.value;
|
|
// min/max limits are enforced here because
|
|
// ui.spinner has issues with extreme max and min values
|
|
if (newValue > max) {
|
|
newValue = max;
|
|
}
|
|
if (newValue < min) {
|
|
newValue = min;
|
|
}
|
|
ctrl.$setViewValue(newValue);
|
|
scope.$apply();
|
|
}
|
|
});
|
|
ctrl.$formatters.unshift(function () {
|
|
var floatValue = parseFloat(ctrl.$modelValue);
|
|
if (isNaN(floatValue)) {
|
|
return ctrl.$modelValue;
|
|
}
|
|
else {
|
|
return floatValue.toFixed(precision);
|
|
}
|
|
});
|
|
// this fix triggers validation on clearing of required input
|
|
var keyUpHandler = function (numberInput, digits) {
|
|
if (digits.length === 1 && digits[0] === '') {
|
|
ctrl.$setViewValue('');
|
|
scope.$apply();
|
|
}
|
|
};
|
|
var radixPoint = i18nService.language === 'de' ? ',' : '.';
|
|
switch (numberType) {
|
|
case 'integer':
|
|
element.inputmask('integer', { rightAlign: false, onKeyUp: keyUpHandler });
|
|
break;
|
|
case 'decimal':
|
|
element.inputmask('decimal', {
|
|
rightAlign: false,
|
|
skipRadixDance: true,
|
|
radixPoint: radixPoint,
|
|
digits: precision,
|
|
onKeyUp: keyUpHandler
|
|
});
|
|
break;
|
|
case 'real':
|
|
element.inputmask('real', {
|
|
rightAlign: false,
|
|
skipRadixDance: true,
|
|
radixPoint: radixPoint,
|
|
digits: precision,
|
|
onKeyUp: keyUpHandler
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
}])
|
|
.directive('menuCustomField', ['customFieldLinkFunction', 'screenConfigurationModel', 'screenConfigurationService',
|
|
'metadataModel', 'objectValueMapperService', '$filter', 'events', '$timeout',
|
|
function (customFieldLinkFunction, screenConfigurationModel, screenConfigurationService, metadataModel, objectValueMapperService, $filter, events, $timeout) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
context: '=',
|
|
isEditable: '=',
|
|
isNew: '=?',
|
|
getFieldValue: '&',
|
|
onSelectCb: '&',
|
|
isHideLabel: '='
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/menu-custom-field.html',
|
|
link: function (scope) {
|
|
customFieldLinkFunction(scope);
|
|
var field = scope.data, context = scope.context, contextType = context && context.ticketType === EntityVO.TYPE_ASSET ? context.ticketType : context.type, classId = context && context.ticketType === EntityVO.TYPE_ASSET ? context.classId : null;
|
|
scope.getCustomFieldFieldValue = scope.getFieldValue();
|
|
scope.onSelectCb = scope.onSelectCb() ? scope.onSelectCb() : angular.noop;
|
|
scope.state = {
|
|
loading: false
|
|
};
|
|
var tooltipPromise;
|
|
if (field.name == 'company') {
|
|
field.isLocationCompany = true;
|
|
}
|
|
scope.$watch('data.setValueFlag', function (value) {
|
|
if (value !== '#$#') {
|
|
if (!_.isEmpty(value)) {
|
|
scope.data.setValue(value);
|
|
scope.data.setLinkedFieldValue(value);
|
|
//Todo: fetch corresponding field option from backend by passing the menu name and value and set them correctly
|
|
/*scope.state.loading = true;
|
|
return scope.loadDynamicSelectionValues(value)
|
|
.then(function (resp) {
|
|
var selectedOption = _.find(resp, function (option) {
|
|
return option.name === value || option.label === value;
|
|
});
|
|
|
|
if (selectedOption) {
|
|
scope.selectItem(selectedOption);
|
|
}
|
|
}).finally(function () {
|
|
scope.state.loading = false;
|
|
scope.data.setValueFlag = '#$#';
|
|
})*/
|
|
}
|
|
else {
|
|
scope.state.loading = false;
|
|
scope.data.clearValue();
|
|
scope.data.clearLinkedFieldValue();
|
|
}
|
|
scope.onFieldValueChange();
|
|
scope.data.setValueFlag = '#$#';
|
|
}
|
|
});
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
metadataModel.getMetadataByType(EntityVO.TYPE_GLOBAL).then(function (metadata) {
|
|
if (metadata.configurationParameters.CustomizationTypeaheadLength) {
|
|
scope.typeaheadMinLength = parseInt(metadata.configurationParameters.CustomizationTypeaheadLength);
|
|
}
|
|
else {
|
|
scope.typeaheadMinLength = 3;
|
|
}
|
|
});
|
|
scope.loadDynamicSelectionValues = function (searchText) {
|
|
return metadataModel.getMetadataByType(contextType).then(function (metadata) {
|
|
var dependencies = {};
|
|
if (contextType === EntityVO.TYPE_TASK || contextType === EntityVO.TYPE_WORKORDER) {
|
|
var locationCompany = context.locationCompany;
|
|
}
|
|
//For new customization types we need to get dependency values from objectValueMapperService as data in context is stale
|
|
if (_.includes(EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION, contextType)) {
|
|
_.forEach(field.dependency, function (dependentField) {
|
|
var fieldObj = objectValueMapperService.getFieldByName(dependentField.name);
|
|
dependencies[dependentField.name] = objectValueMapperService.getExactValueByFieldName(dependentField.name) || null;
|
|
//since there is no locationcompnay field for Incident create, we need to use the customer company value
|
|
if (!fieldObj && dependentField.name === 'locationCompany') {
|
|
fieldObj = objectValueMapperService.getFieldByName('company');
|
|
dependencies[dependentField.name] = objectValueMapperService.getExactValueByFieldName('company');
|
|
if (dependencies[dependentField.name] === '') {
|
|
dependencies[dependentField.name] = locationCompany;
|
|
}
|
|
}
|
|
if (fieldObj && fieldObj.dataType === 'dropdown') {
|
|
if (fieldObj.options && fieldObj.options.length > 0) {
|
|
_.forEach(fieldObj.options, function (option) {
|
|
if (option.name === dependencies[dependentField.name]) {
|
|
dependencies[dependentField.name] = option.index;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
else if (fieldObj && fieldObj.dataType === 'widget' && fieldObj.members.length && fieldObj.members[0].dataType === 'dropdown') {
|
|
if (fieldObj.members[0].options && fieldObj.members[0].options.length > 0) {
|
|
_.forEach(fieldObj.members[0].options, function (option) {
|
|
if (option.name === dependencies[dependentField.name]) {
|
|
dependencies[dependentField.name] = option.index;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
_.forEach(field.dependency, function (dependentField) {
|
|
dependencies[dependentField.name] = scope.getCustomFieldFieldValue(dependentField.name); //get value for custom field (lookup in fieldsConfig and in context.customFields.fieldName)
|
|
if (_.isUndefined(dependencies[dependentField.name]) && contextType !== 'asset') {
|
|
//Warning:: Special handling for fields done here, but should have been handled by backend
|
|
//As agreed backend will either send the field and metadata mapping or accept the name in the field object for dependencies on dropdown fields
|
|
//e.g. In the menu/expand/ call we will send {priority: "High"} instead of {priority: 2}
|
|
//Due to time constraints this was hardcoded in UC instead of backend handling
|
|
var specialFieldsList = [EntityVO.TYPE_PRIORITY, EntityVO.TYPE_URGENCY, EntityVO.TYPE_IMPACT, EntityVO.TYPE_STATUS];
|
|
dependencies[dependentField.name] = screenConfigurationService.getContextPropertyByMetadataMapping(context, metadata, dependentField.name, scope.isNew) || null;
|
|
if (dependencies[dependentField.name] !== null && dependencies[dependentField.name] !== undefined
|
|
&& (contextType === EntityVO.TYPE_KNOWNERROR || contextType === EntityVO.TYPE_PROBLEM)
|
|
&& _.includes(specialFieldsList, dependentField.name)) {
|
|
var optionsList;
|
|
switch (dependentField.name) {
|
|
case EntityVO.TYPE_PRIORITY:
|
|
optionsList = metadata.priorities;
|
|
break;
|
|
case EntityVO.TYPE_URGENCY:
|
|
optionsList = metadata.urgencies;
|
|
break;
|
|
case EntityVO.TYPE_IMPACT:
|
|
optionsList = metadata.impacts;
|
|
break;
|
|
case EntityVO.TYPE_STATUS:
|
|
optionsList = metadata.statuses;
|
|
break;
|
|
default:
|
|
optionsList = [];
|
|
break;
|
|
}
|
|
if (optionsList.length) {
|
|
dependencies[dependentField.name] = _.result(_.find(optionsList, { 'name': dependencies[dependentField.name] }), 'index');
|
|
}
|
|
}
|
|
}
|
|
else if (_.isUndefined(dependencies[dependentField.name]) && contextType === 'asset') {
|
|
//DRSMX-66920 : Menu dependency in SmartIT not working as expected
|
|
//When dependent field names are different than the field names coming in the asset metaData, backend is expecting to pass the dependent fieldNames as per metaData
|
|
var metaDataKey = metadata && metadata.ootbMapping && metadata.ootbMapping[dependentField.name] && metadata.ootbMapping[dependentField.name][0];
|
|
if (metaDataKey && metaDataKey !== dependentField.name) {
|
|
var dependentFieldValue = screenConfigurationService.getContextPropertyByMetadataMapping(context, metadata, dependentField.name);
|
|
if (!dependentFieldValue && metaDataKey === 'companyName') {
|
|
dependentFieldValue = context && context.company && context.company.name ? context.company.name : '';
|
|
}
|
|
else if (!dependentFieldValue && metaDataKey === 'siteGroup') {
|
|
dependentFieldValue = context && context.site && context.site.siteGroup ? context.site.siteGroup : '';
|
|
}
|
|
else if (!dependentFieldValue && metaDataKey === 'siteName') {
|
|
dependentFieldValue = context && context.site && context.site.name ? context.site.name : '';
|
|
}
|
|
else if (!dependentFieldValue && metaDataKey === 'siteRegion') {
|
|
dependentFieldValue = context && context.site && context.site.region ? context.site.region : '';
|
|
}
|
|
delete dependencies[dependentField.name];
|
|
dependencies[metaDataKey] = dependentFieldValue ? dependentFieldValue : null;
|
|
}
|
|
else {
|
|
dependencies[dependentField.name] = screenConfigurationService.getContextPropertyByMetadataMapping(context, metadata, dependentField.name);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
var hasCreateScreen = scope.isNew && _.includes([EntityVO.TYPE_PROBLEM, EntityVO.TYPE_KNOWNERROR], contextType) ? false : scope.isNew;
|
|
return screenConfigurationModel.loadDynamicSelectionFieldLabels(contextType, field.menu, searchText, dependencies, classId, field.name, hasCreateScreen).then(function (data) {
|
|
if (tooltipPromise) {
|
|
$timeout.cancel(scope.tooltipPromise);
|
|
}
|
|
scope.exceedsChunkSize = data.exceedsChunkSize;
|
|
scope.state.isTooltipOpen = data.exceedsChunkSize;
|
|
tooltipPromise = $timeout(function () {
|
|
scope.state.isTooltipOpen = false;
|
|
}, 10000);
|
|
return data.items;
|
|
});
|
|
}).finally(function () {
|
|
scope.state.loading = false;
|
|
});
|
|
};
|
|
scope.onInputFocusBlur = function () {
|
|
scope.state.isTooltipOpen = false;
|
|
};
|
|
scope.selectItem = function (option) {
|
|
var newFieldValue;
|
|
if (!_.isEmpty(option)) {
|
|
if (field.name === 'assignee' || field.name === 'assigneeName' || field.name === 'managerName') {
|
|
newFieldValue = option.label;
|
|
field.assigneeLoginId = option.value;
|
|
}
|
|
else {
|
|
//handle 'case 3', option -> {label: 'aaa', value: 'bbb'} && _.isUndefined(field.valueField) == true -> set value instead of label to field
|
|
newFieldValue = (!field.valueField && option.value) ? option.value : option.label;
|
|
}
|
|
field.setValue(newFieldValue);
|
|
field.setLinkedFieldValue(option.value);
|
|
if (_.includes(EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION, contextType) && field.valueField) {
|
|
objectValueMapperService.setByProperty(field.valueField, 'value', option.value);
|
|
}
|
|
scope.$emit(events.CLEAR_DEPENDANT_FIELDS, field.name);
|
|
}
|
|
else {
|
|
field.clearValue();
|
|
field.clearLinkedFieldValue();
|
|
if (_.includes(EntityVO.ENTITIES_WITH_NEW_CUSTOMIZATION, contextType) && field.valueField) {
|
|
objectValueMapperService.setByProperty(field.valueField, 'value', '');
|
|
}
|
|
}
|
|
scope.onFieldValueChange();
|
|
scope.onSelectCb();
|
|
scope.$emit(events.CUSTOM_FIELD_VALUE_CHANGE);
|
|
};
|
|
}
|
|
};
|
|
}])
|
|
.directive('groupCustomField', ['customFieldLinkFunction', 'events', 'screenConfigurationService', 'metadataModel', '$filter', 'objectValueMapperService',
|
|
function (customFieldLinkFunction, events, screenConfigurationService, metadataModel, $filter, objectValueMapperService) {
|
|
return {
|
|
restrict: 'E',
|
|
replace: true,
|
|
scope: {
|
|
data: '=',
|
|
context: '=',
|
|
getFieldValue: '&',
|
|
isNew: '=?',
|
|
isHideLabel: '='
|
|
},
|
|
templateUrl: 'views/field-customization/custom-fields/group-custom-field.html',
|
|
controller: 'LaunchActionController',
|
|
link: function (scope) {
|
|
var context = scope.context, contextType = context && context.ticketType === EntityVO.TYPE_ASSET ? context.ticketType : context.type;
|
|
customFieldLinkFunction(scope);
|
|
scope.$watch('$parent.editMode', function (newValue) {
|
|
scope.editMode = newValue;
|
|
}, true);
|
|
scope.$watch('context', function () {
|
|
scope.checkEditable();
|
|
}, true);
|
|
scope.getFieldValue = scope.getFieldValue();
|
|
scope.isEditable = function (field) {
|
|
if (scope.context.type === EntityVO.TYPE_ASSET) {
|
|
return !field.isReadOnly;
|
|
}
|
|
else {
|
|
return field.isEditable(scope.context.accessMappings);
|
|
}
|
|
};
|
|
if (scope.isHideLabel) {
|
|
scope.tooltipToShow = $filter('customFieldLabelI18n')(scope.data);
|
|
}
|
|
scope.clearDependantFieldValues = function (event, fieldName) {
|
|
_.forEach(scope.data.members, function (groupField) {
|
|
if (!groupField.dependency || !groupField.dependency.length) {
|
|
groupField.groupEditable = true;
|
|
return;
|
|
}
|
|
else if (_.findIndex(groupField.dependency, { name: fieldName }) > -1) {
|
|
groupField.clearValue();
|
|
groupField.clearLinkedFieldValue();
|
|
scope.onFieldValueChange(groupField);
|
|
}
|
|
});
|
|
};
|
|
//todo: minimize calls of function (tier3 changed -> no need to check editability of tier1)
|
|
scope.checkEditable = function () {
|
|
var editGroup = true;
|
|
metadataModel.getMetadataByType(contextType).then(function (metadata) {
|
|
_.forEach(scope.data.members, function (groupField) {
|
|
if (!groupField.dependency || !groupField.dependency.length) {
|
|
groupField.groupEditable = true;
|
|
return;
|
|
}
|
|
_.forEach(groupField.dependency, function (dependency) {
|
|
if (!scope.getFieldValue(dependency.name)) {
|
|
var fieldValue = objectValueMapperService.getExactValueByFieldName(dependency.name);
|
|
if (!fieldValue) {
|
|
editGroup = false;
|
|
}
|
|
}
|
|
});
|
|
if (!editGroup) {
|
|
groupField.groupEditable = false;
|
|
groupField.clearValue();
|
|
groupField.clearLinkedFieldValue();
|
|
scope.onFieldValueChange(groupField);
|
|
}
|
|
else {
|
|
groupField.groupEditable = true;
|
|
}
|
|
});
|
|
});
|
|
};
|
|
scope.checkEditable();
|
|
scope.$on(events.REFRESH_FIELD_VALUES, scope.checkEditable);
|
|
scope.$on(events.CLEAR_DEPENDANT_FIELDS, scope.clearDependantFieldValues);
|
|
}
|
|
};
|
|
}]);
|
|
}());
|