SmartIT_Extensions/BMC/smart-it-full-helix/scripts/app/common/edit-summary-directive.js

425 lines
22 KiB
JavaScript

"use strict";
(function () {
'use strict';
angular.module('myitsmApp')
.directive('editable', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
/* view -> model */
function keyUpClickHandler() {
scope.$apply(function () {
ctrl.$setViewValue(elm.text());
});
}
elm.on('keyup click', keyUpClickHandler);
scope.$on("$destroy", function () {
console.log("editable: unbind events");
elm.off('keyup', keyUpClickHandler);
elm.off('click', keyUpClickHandler);
});
/* model -> view */
ctrl.$render = function () {
if (_.isUndefined(ctrl.$viewValue)) {
elm.text('');
}
else {
elm.text(ctrl.$viewValue);
}
};
}
};
})
.directive('editSummary', ['events', '$timeout', 'attachmentService', 'ticketModel', '$q', 'systemAlertService', 'i18nService',
'$filter', '$compile', 'objectValueMapperService', '$rootScope',
function (events, $timeout, attachmentService, ticketModel, $q, systemAlertService, i18nService, $filter, $compile, objectValueMapperService, $rootScope) {
return {
restrict: 'E',
templateUrl: 'views/common/edit-summary-directive.html',
replace: true,
scope: {
ticket: '=',
context: '=',
textAreaName: '@',
textplaceholder: '=',
isDescRequired: '=',
updateIsHandledByParent: '=',
dropable: '=',
label: '@',
editDisabled: '=',
type: '=',
editMode: '=?',
data: '=?',
isEditable: '=?',
showAttachmentIcon: '=?',
descLimit: '=?'
},
link: function (scope, element, attr) {
var container = element.find('.ticket-summary__content'), textAreaObject = container.find('textarea.content');
var originalAttachment = _.cloneDeep(scope.ticket.attachments);
function init() {
if (!_.isBoolean(scope.isEditable)) {
scope.isEditable = true;
}
if (_.isUndefined(scope.ticket.attachments)) {
scope.ticket.attachments = [];
}
if (_.isUndefined(scope.ticket.desc)) {
scope.ticket.desc = '';
}
if (scope.isDescRequired) {
textAreaObject.prop('required', true);
textAreaObject.attr('aria-required', 'true');
}
if ((scope.ticket.workNote && scope.ticket.workNote.locked) || !scope.isEditable) {
scope.isLocked = true;
}
scope.descCopy = scope.ticket.desc;
scope.attachments = scope.ticket.attachments;
scope.state = {
descriptionChanged: false
};
scope.showAttachment = scope.ticket.type === EntityVO.TYPE_CHANGE ? false : attr.attachment === 'true';
scope.descLimit = attr.descLimit ? parseInt(attr.descLimit, 10) : '';
scope.attachmentLimit = scope.showAttachment && attr.attachmentLimit ? parseInt(attr.attachmentLimit, 10) : 9999;
if (scope.ticket.type === EntityVO.TYPE_TASK) {
scope.attachmentLimit = 3;
}
scope.attachmentToUpload = [];
scope.attachmentToDelete = [];
scope.attachmentDropped = false;
scope.textAreaIsFocused = false;
if (scope.data) {
_.each(scope.data.members, function (member) {
if (member.required) {
scope.data.isRequired = member.required;
}
});
}
scope.$on(events.AFTER_SAVED_CHANGES, afterSaveChangesHandler);
scope.$on(events.TOGGLE_EDIT_MODE, handleToggleEditMode);
scope.$on(events.SAVE_CHANGES, handleSaveChanges);
scope.$on(events.SAVE_ALL_CHANGES_COMPLETE, handleSaveAllChangesComplete);
scope.$on(events.DISCARD_CHANGES, handleDiscardChanges);
scope.$on(events.DESC_CHANGED, function () {
scope.descCopy = scope.ticket.desc;
});
scope.$on(events.CLEAR_DESC, function () {
scope.descCopy = '';
if (scope.ticket) {
scope.ticket.desc = '';
}
});
var unbindRootScopeListener = $rootScope.$on(events.TICKET_TEMPLATE_UPDATED, function (e, value) {
if (scope.ticket.ticketType !== value.ticketType) {
return;
}
scope.descCopy = value.desc;
if (scope.data) {
scope.data.value.desc = scope.descCopy;
scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: scope.data.name });
}
});
scope.$watch('descCopy', function () {
adjustDescriptionHeight();
});
scope.$on('$destroy', function () {
unbindRootScopeListener();
container = null;
textAreaObject = null;
});
}
if (scope.data) {
scope.$watch('data.setValueFlag', function (value) {
if (value && value !== '#$#') {
scope.descCopy = value;
scope.onTicketDescriptionChange();
scope.data.setValueFlag = '#$#';
}
});
}
/**
* Handle file change
* @param inputDOM
*/
scope.handleFileChange = function (inputDOM) {
var attachment = attachmentService.prepareFileToUpload({ fileInput: inputDOM });
if (attachment && attachment.size <= 0) {
systemAlertService.warning({
text: $filter('i18n')('attachment.file_empty'),
icon: 'icon-exclamation_triangle',
clear: true,
hide: 5000
});
return;
}
if (attachment) {
//Defect #SW00488589. When attaching a file, then removing it and then attaching it again
//onchange event is not firing, because input receives same file, so from DOM state perspective nothing has changed
inputDOM.value = null;
var inputClone = angular.element(inputDOM.cloneNode());
$compile(inputClone)(scope);
angular.element(inputDOM)
.before(inputClone)
.remove();
$timeout(function () {
inputClone.focus();
scope.attachments.push(attachment);
if (scope.context && scope.context === 'detail') {
scope.attachmentToUpload.push(attachment);
}
var descField = objectValueMapperService.getFieldByName('desc');
if (descField) {
// process attachments to upload
if (_.size(scope.attachmentToUpload)) {
descField.value.attachmentToUpload = scope.attachmentToUpload;
}
}
});
}
};
/**
* Handle attachment dismissal
*
* @param $event
* @param attachment
*/
scope.dismissAttachment = function ($event, attachment) {
attachmentService.dismissAttachment(scope, $event, attachment, scope.context);
var node = $event.currentTarget;
angular.element(node).parents('div.editable-summary').find('textarea').focus();
};
/**
* Handle click on attachment
*
* @param attachment
*/
scope.handleAttachmentClick = function (attachment) {
if (scope.context === 'draft' || scope.context === 'create') {
return false;
}
else {
attachmentService.getAttachmentFile(scope.ticket.type ? scope.ticket.type : scope.type, attachment);
}
};
/**
* Switch to edit mode.
*/
scope.edit = function () {
//May have set value so refer data object if present
if (scope.data && scope.data.value) {
scope.descCopy = scope.data.value.desc;
}
else {
scope.descCopy = _.clone(scope.ticket.desc);
}
scope.editMode = true;
adjustDescriptionHeight();
};
/**
* Collect changes
*
* @returns {Object}
*/
function collectChanges() {
if (scope.state.descriptionChanged) {
return { desc: scope.descCopy };
}
else {
return {};
}
}
function draftModeEnabled() {
return scope.context === 'draft';
}
/**
* Save changes
* @returns {Array}
*/
scope.save = function () {
var promiseArray = [];
var isDraft = draftModeEnabled();
var changes = collectChanges();
var singleMode = !scope.updateIsHandledByParent;
if (!isDraft) {
if (_.size(changes) && singleMode) {
promiseArray.push(ticketModel.update(scope.ticket.id, scope.ticket.type, changes));
}
// process attachments to upload
if (_.size(scope.attachmentToUpload)) {
promiseArray.push(attachmentService.uploadAttachment(scope.ticket.type, scope.ticket.id, scope.attachmentToUpload)
.then(function (response) {
var attachments = _.union(scope.attachments, response);
scope.attachments = _.filter(attachments, function (attach) {
return !attach.pendingSave;
});
}));
}
// process attachments to delete
if (_.size(scope.attachmentToDelete)) {
_.each(scope.attachmentToDelete, function (attachment) {
promiseArray.push(attachmentService.deleteAttachment(scope.ticket.type, {
dataSourceId: attachment.attachmentReference.dataSourceId,
attachmentId: attachment.attachmentReference.attachmentId
}));
});
}
}
$q.all(promiseArray).then(function () {
//scope.ticket.desc = scope.descCopy; //SW00560919 - custom filter description issue
closeEditor();
// remove attachmentToDelete from attachments
scope.ticket.attachments = scope.attachments = _.without(scope.attachments, scope.attachmentToDelete);
scope.attachmentToUpload = [];
scope.attachmentToDelete = [];
scope.$emit(events.SAVE_CHANGES_REQUEST, changes, singleMode || isDraft);
}).catch(function (error) {
scope.cancel();
if (error) {
systemAlertService.error({
text: (error.data && error.data.error) || error,
clear: false
});
}
//scope.$emit(events.SAVE_CHANGES_REQUEST, changes, singleMode || isDraft); //if wants to complete request in case of failure then uncomment this code
});
return promiseArray;
};
scope.cancel = function () {
scope.attachmentToDelete = [];
scope.attachmentToUpload = [];
scope.descCopy = _.clone(scope.ticket.desc); //to avoid having edited text back in view mode
scope.attachments = _.cloneDeep(originalAttachment); //to avoid attachment edit reflecting in view mode
scope.ticket.attachments = _.cloneDeep(originalAttachment);
if (scope.data) {
scope.data.value.desc = scope.descCopy;
scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: scope.data.name });
}
closeEditor();
};
/**
* Handle ticket description change
*/
scope.onTicketDescriptionChange = function () {
var elem = element.find('.ticket-summary__content');
var textAreaObject = elem.find('textarea.content');
var editableContent = angular.element.find('.editable-content-section__content');
var prevHeight = textAreaObject[0].offsetHeight;
var height = textAreaObject[0].scrollHeight;
textAreaObject.css('height', 'auto');
if (height > 0) {
textAreaObject.css('height', height + 'px');
if (editableContent && editableContent.length) {
jQuery(editableContent).scrollTop(editableContent[0].scrollTop + (height - prevHeight));
}
}
scope.$emit(events.FIELD_FORM_IS_DIRTY);
scope.state.descriptionChanged = true;
if (scope.context === 'create') {
scope.ticket.desc = scope.descCopy;
}
if (scope.descLimit && scope.ticket.desc && scope.ticket.desc.length > scope.descLimit) {
scope.ticket.desc = $filter('limitTo')(scope.ticket.desc, scope.descLimit);
}
if (scope.data && (scope.descCopy || scope.descCopy === '') && scope.data.value.desc !== scope.descCopy) {
scope.data.value.desc = scope.descCopy;
scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: scope.data.name, memberName: scope.data.name });
}
};
if (scope.descLimit > 0) {
element.find('.content').attr('maxlength', scope.descLimit);
}
scope.viewSummaryExpandable = function () {
var maxDescriptionHeight = 100, elem = element.find('.ticket-summary__content'), viewSummaryDiv = elem.find('div.content');
return !scope.editMode
&& scope.context !== "create"
&& (viewSummaryDiv[0].scrollHeight > maxDescriptionHeight
|| scope.attachmentsCountOverLimit() > 0);
};
scope.summaryExpandable = function () {
var maxDescriptionHeight = 100;
return !scope.editMode
&& scope.context !== "create"
&& (textAreaObject[0].scrollHeight > maxDescriptionHeight
|| scope.attachmentsCountOverLimit() > 0);
};
scope.attachmentsCountOverLimit = function () {
var attachmentCountLimit = 4;
return (scope.attachments || []).length > attachmentCountLimit
? scope.attachments.length - attachmentCountLimit
: 0;
};
scope.summaryCollapsed = function () {
return !scope.summaryExpanded && scope.summaryExpandable();
};
scope.viewSummaryCollapsed = function () {
return !scope.summaryExpanded && scope.viewSummaryExpandable();
};
scope.showMoreVisible = function () {
return !scope.summaryExpanded && scope.viewSummaryExpandable();
};
scope.showLessVisible = function () {
return scope.summaryExpanded && scope.viewSummaryExpandable();
};
scope.toggleSummary = function () {
scope.summaryExpanded = !scope.summaryExpanded;
$timeout(function () {
textAreaObject.scrollTop(0);
});
};
scope.filteredAttachments = function () {
return scope.summaryCollapsed()
? scope.attachments.slice(0, 4)
: scope.attachments;
};
/**
* Close edit mode.
*/
function closeEditor() {
scope.editMode = false;
scope.state.descriptionChanged = false;
if (!scope.updateIsHandledByParent || draftModeEnabled()) {
scope.$emit(events.SAVE_CHANGES_COMPLETE);
}
}
function handleToggleEditMode() {
if (!scope.editMode && !scope.editDisabled) {
scope.edit();
}
}
function handleSaveChanges() {
scope.save();
}
function handleSaveAllChangesComplete() {
scope.ticket.desc = scope.descCopy;
if (scope.updateIsHandledByParent && !scope.ticket.isDraft) {
closeEditor();
}
}
function handleDiscardChanges() {
scope.cancel();
}
function adjustDescriptionHeight() {
var scrollHeightAdjustment = 14;
$timeout(function () {
textAreaObject && textAreaObject.height(textAreaObject[0].scrollHeight - scrollHeightAdjustment);
});
}
function afterSaveChangesHandler() {
var descField = objectValueMapperService.getFieldByName('desc');
if (!scope.ticket.isDraft && descField) {
descField.value.attachmentToUpload = [];
descField.value.attachmentToDelete = [];
scope.attachmentToDelete = [];
scope.attachmentToUpload = [];
scope.attachments = _.cloneDeep(scope.ticket.attachments);
originalAttachment = _.cloneDeep(scope.ticket.attachments);
}
closeEditor();
}
init();
}
};
}]);
}());