"use strict"; (function () { 'use strict'; /** * @ngdoc directive * @name myitsmApp:emailRecipient * @restrict E * @desription emailRecipient directive is designed for user to search and input recipient */ angular.module('myitsmApp') .directive('emailRecipient', ['$timeout', '$q', 'i18nService', 'createTicketModel', 'userModel', 'personModel', 'collisionModel', 'browser', function ($timeout, $q, i18nService, createTicketModel, userModel, personModel, collisionModel, browser) { var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i; return { restrict: 'E', templateUrl: 'components/email/email-recipient.html', replace: true, scope: { label: '@', recipientList: '=', ticketData: '=', inputText: '=' }, link: function (scope, $element) { scope.userModel = userModel; var keyCodes = { backspace: 8, enter: 13, leftArrow: 37, rightArrow: 39, upArrow: 38, downArrow: 40, space: 32, comma: 188, semiColon: 186, semiColon_FF: 59 // Fire Fox use 59 }, inputElement = $element.find('span.email__recipient-input'), blurTimer = null; scope.defaultListLoading = false; scope.getList = function (type, term) { if (term === '***' && scope.ticketData.length === 1) { var defaultSelectionList = []; var promises = []; var ticketData = scope.ticketData[0]; var defaultPersonTypeList = [ { name: 'customer', label: 'common.label.customer' }, { name: 'contact', label: 'common.label.contact' }, { name: ticketData.type === EntityVO.TYPE_RELEASE ? 'coordinator' : 'assignee', label: 'common.labels.assignee' }, { name: 'manager', label: 'create.workorder.requestmanager' } ]; if (ticketData.type === EntityVO.TYPE_CHANGE) { defaultPersonTypeList.push({ name: 'collisionManagers', label: 'change.detail.emailRecipients.allCollisionManagers' }); } //From Console, release ticketdata does not have assignee, it has releaseCoordinator if (ticketData.type === EntityVO.TYPE_RELEASE && ticketData.releaseCoordinator != null) { defaultPersonTypeList.push({ name: 'releaseCoordinator', label: 'common.labels.assignee' }); } //From Console, problem / knownerror ticketdata does not have coordinator or manager, it has problemCoordinator if ((ticketData.type === EntityVO.TYPE_PROBLEM || ticketData.type === EntityVO.TYPE_KNOWNERROR) && ticketData.problemCoordinator != null) { defaultPersonTypeList.push({ name: 'problemCoordinator', label: 'problem.details.coordinator' }); } else if ((ticketData.type === EntityVO.TYPE_PROBLEM || ticketData.type === EntityVO.TYPE_KNOWNERROR) && ticketData.coordinator != null) { defaultPersonTypeList.push({ name: 'coordinator', label: 'problem.details.coordinator' }); } _.each(defaultPersonTypeList, function (defaultPersonType) { var person; if (ticketData[defaultPersonType.name] && ticketData[defaultPersonType.name].loginId) { person = ticketData[defaultPersonType.name]; if (!person.fullName && (person.firstName || person.lastName)) { person.fullName = person.firstName + ' ' + person.lastName; } person.type = i18nService.getLocalizedString(defaultPersonType.label); if (!person.email) { scope.defaultListLoading = true; var promise = personModel.getPersonDetailsByID(person.loginId) .then(function (personData) { if (personData) { person.email = personData.email ? personData.email : ''; person.company = {}; person.company.name = personData.company ? personData.company.name : ''; defaultSelectionList.push(person); } }); promises.push(promise); } else { defaultSelectionList.push(person); } } if (defaultPersonType.name === 'collisionManagers') { scope.defaultListLoading = true; person = { isPersonList: true, type: i18nService.getLocalizedString(defaultPersonType.label), personList: [], companySummary: [], emailSummary: [] }; var collisionsPromise = collisionModel.getListOfCollisionsById(ticketData, false); collisionsPromise.then(function (collisions) { if (collisions && collisions.count > 0) { var personList = []; _.each(collisions.changeList, function (change) { personList.push(change.assignee); }); person.personList = _.uniqBy(personList, 'id'); var allFullNames = []; _.each(person.personList, function (item) { //Currently backend will figure out recipient email using loginId on its own item.loginId = item.id; item.company = {}; allFullNames.push(item.fullName); }); person.combinedNames = allFullNames.join(); defaultSelectionList.push(person); } }); promises.push(collisionsPromise); } }); return $q.all(promises).then(function () { scope.defaultListLoading = false; return defaultSelectionList; }); } else { //if multiple tickets selected , then show all from person if (term === '***') { term = '%%%'; } return createTicketModel.getList(type, term, null, null, true).then(function (response) { return response.items; }); } }; scope.removeRecipient = function (recipient) { if (scope.recipientList) { var index = scope.recipientList.indexOf(recipient); if (index >= 0) { scope.recipientList.splice(index, 1); } } }; scope.focusInput = function () { inputElement.focus(); }; scope.handleBlurEvent = function () { scope.typeaheadLoading = false; if (!blurTimer) { $timeout.cancel(blurTimer); } blurTimer = $timeout(function () { if (scope.inputText && EMAIL_REGEXP.test(scope.inputText)) { addRecipient(scope.inputText); inputElement.empty(); } }, 200); }; scope.handleKeydown = function ($event) { switch ($event.keyCode || $event.which) { case keyCodes.backspace: var inputText = inputElement.text().trim(); if (inputText.length === 0) { removeLastRecipient(); scope.focusInput(); $event.stopPropagation(); } else if (inputText.length === 1 && browser.isEdge) { inputElement.text(''); $event.stopPropagation(); } break; // These are valid recipient separators case keyCodes.enter: if (scope.inputText.length > 0) { addRecipient(scope.inputText); inputElement.empty(); scope.focusInput(); } $event.stopPropagation(); $event.preventDefault(); break; } }; scope.onTextChange = function () { if (scope.inputText && scope.inputText !== '***') { var lastChar = scope.inputText.substr(scope.inputText.length - 1); if ([',', ';'].indexOf(lastChar) >= 0) { if (scope.inputText.length > 0) { addRecipient(scope.inputText.substr(0, scope.inputText.length - 1)); inputElement.empty(); scope.focusInput(); } } } }; scope.onRecipientSelect = function ($item) { if ($item.isPersonList) { _.each($item.personList, function (person) { addRecipient(person.email, person.fullName, person.id, $item.type); inputElement.empty(); }); } if ($item.email) { addRecipient($item.email, $item.fullName, $item.loginId, $item.type); inputElement.empty(); } scope.focusInput(); }; function addRecipient(recipientEmail, fullName, loginId, type) { scope.recipientList.push({ email: recipientEmail, fullName: fullName ? fullName : recipientEmail, loginId: loginId, internal: !!loginId, type: type || '' }); } function removeLastRecipient() { var index = scope.recipientList.length; if (index > 0) { scope.recipientList.splice(index - 1, 1); } } function init() { $timeout(function () { if (scope.inputText.length) { inputElement.text(scope.inputText); } if (scope.recipientList.length > 0) { _.each(scope.recipientList, function (recipient) { if (!recipient.email) { personModel.getPersonDetailsByID(recipient.id) .then(function (profile) { recipient.email = profile.email; recipient.loginId = profile.loginId; recipient.internal = !!recipient.loginId; }); } }); } scope.focusInput(); }, 0); } init(); } }; }]) .directive('bindContenteditable', ['$timeout', function ($timeout) { return { restrict: 'A', require: '?ngModel', scope: { isDisabled: '=' }, link: function (scope, element, attrs, ngModel) { var previousValue = ''; var keyCodes = { upArrow: 38, downArrow: 40, escape: 27 }; if (!ngModel) { return; } function blurKeyupChangeHandler($event) { if ($event.keyCode === keyCodes.downArrow && previousValue === '') { scope.$apply(loadDefaultList); $event.stopPropagation(); $event.preventDefault(); } else if (($event.keyCode === keyCodes.upArrow || $event.keyCode === keyCodes.downArrow) && previousValue === '***') { return; } else if ($event.keyCode === keyCodes.escape) { ngModel.$setViewValue(''); } else if (scope.isDisabled) { element.empty(); $event.stopPropagation(); $event.preventDefault(); } else { $timeout(function () { read(); }); } } function keyDownHandler($event) { if (scope.isDisabled) { element.empty(); $event.stopPropagation(); $event.preventDefault(); } } element.on('blur keyup change', blurKeyupChangeHandler); element.on('keydown', keyDownHandler); scope.$on('$destroy', function () { console.log('emailRecipientGraph: unbind events'); element.off('blur', blurKeyupChangeHandler); element.off('keyup', blurKeyupChangeHandler); element.off('change', blurKeyupChangeHandler); element.off(); }); read(); function read() { var newValue = element.text().trim(); // call $setViewValue only when there is a change, otherwise it will // false trigger the typeahead directive if (previousValue !== newValue) { previousValue = newValue; ngModel.$setViewValue(newValue); } } function loadDefaultList() { ngModel.$setViewValue('***'); } } }; }]); }());