"use strict"; /** * Created by igor.samulenko on 6/23/2014. */ (function () { 'use strict'; angular.module('myitsmApp') .directive('editableContentSection', function () { return { restrict: 'E', replace: true, transclude: true, scope: { editModeAllowed: '=', hideEditButton: '=', ticket: '=', editButtonLabel: '=' }, templateUrl: 'views/common/editable-content-section.html', controller: ['$element', '$transclude', '$scope', '$timeout', 'events', 'ticketModel', 'assetModel', function ($element, $transclude, $scope, $timeout, events, ticketModel, assetModel) { var childScope, transcludedContent; var forms = []; var combinedChanges = {}; var editableBlockCount = 0; var combinedBlocksCount = 0; var processedEventsCount = 0; var savedEventsCount = 0; $scope.editMode = false; $scope.dataSaving = false; $scope.editableContentInvalid = false; $transclude(function (clone, scope) { childScope = scope; childScope.handleExternalEditClick = function () { $scope.onEditButtonClick(); }; childScope.$on(events.SAVE_CHANGES_REQUEST, handleSaveChangesRequest); childScope.$on(events.SAVE_CHANGES_COMPLETE, handleSaveChangesComplete); childScope.$on(events.SAVE_CHANGES_FAULT, handleSaveChangesFault); childScope.$on(events.SAVE_CHANGES_FAULT_CONTINUE, handleSaveChangesFaultContinue); // perform manual transclusion var editableContentHolder = $element.find('div.editable-content-section__content'); editableContentHolder.append(clone); // find forms if any exist var formArray = editableContentHolder.find('form'); if (formArray.length) { _.forEach(formArray, function (element) { forms.push(element.name); }); } // track amount of editable blocks editableBlockCount = editableContentHolder.find('.editable-content-section-block').length; transcludedContent = clone; }); $scope.$on(events.DISABLE_EDIT, function (event, childEditMode) { $scope.isChildInContent = childEditMode; }); /** * Handle edit click */ $scope.onEditButtonClick = function () { var elementId = getElementId(); resetState(); childScope.$broadcast(events.TOGGLE_EDIT_MODE, elementId); childScope.$broadcast(events.TOGGLE_DYNAMIC_FIELD_EDIT_MODE, elementId); $scope.editMode = !$scope.editMode; childScope.editMode = !childScope.editMode; $timeout(updateRequiredFieldsLabelVisibility); $timeout(focusFirstInput, 100); // notify parents $scope.$emit(events.TOGGLE_EDIT_MODE, elementId); $scope.$emit(events.DISABLE_PARENT_EDITMODE, true); $scope.$emit(events.DISABLE_CHILD_EDITMODE, true); }; function focusFirstInput() { $element.find('input[type="text"]').first().focus(); } /** * Handle save click */ $scope.onSaveClick = function () { var editableContentHolder = $element.find('div.editable-content-section__content'); editableBlockCount = editableContentHolder.find('.editable-content-section-block').length; childScope.$broadcast(events.SAVE_CHANGES); $scope.$emit(events.DISABLE_PARENT_EDITMODE, false); $scope.$emit(events.DISABLE_CHILD_EDITMODE, false); }; /** * Handle cancel click */ $scope.onCancelClick = function () { childScope.$broadcast(events.DISCARD_CHANGES); $scope.$emit(events.DISABLE_PARENT_EDITMODE, false); $scope.$emit(events.DISABLE_CHILD_EDITMODE, false); closeEditMode(); }; $scope.editableContentIsInvalid = function () { var result = false; if (forms && forms.length) { try { _.forEach(forms, function (formName) { var form = _.get(childScope, formName) || childScope[formName]; result = result || form.$invalid; }); } catch (error) { //ignore it } } $scope.editableContentInvalid = result; return result; }; function handleSaveChangesRequest(event, eventData, singleMode, isCustomField) { startSaving(); if (editableBlockCount > 0) { if (eventData && _.size(eventData) && !singleMode) { if (eventData.customFields) { combinedChanges.customFields = angular.extend(combinedChanges.customFields || {}, eventData.customFields); } else { angular.extend(combinedChanges, eventData); } } //custom fields also emits SAVE_CHANGES_REQUEST and this will cause process count over run editable content count if (!isCustomField) { processedEventsCount++; } combinedBlocksCount += singleMode ? 0 : 1; console.log('processed ' + processedEventsCount + ' events'); if (processedEventsCount === editableBlockCount) { console.log('all editable block events processed'); if (_.size(combinedChanges)) { console.log('combined changes object:'); console.log(combinedChanges); // perform update if (combinedChanges.isAssetUpdate) { delete combinedChanges.isAssetUpdate; assetModel.update(combinedChanges).then(handleSaveAllChangesSuccess, handleSaveAllChangesFault); } else { ticketModel.update($scope.ticket.id, $scope.ticket.type, combinedChanges) .then(function (result) { if (result.data && result.data.error) { childScope.$broadcast(events.DISCARD_CHANGES); closeEditMode(); } else { handleSaveAllChangesSuccess(result); } }, handleSaveAllChangesFault); } } else { console.log('nothing changed or child sections saved themselves, closing edit mode'); handleSaveAllChangesSuccess({}); } } } } /** * Handle successful update * * @param {Object} response */ function handleSaveAllChangesSuccess(response) { childScope.$broadcast(events.SAVE_ALL_CHANGES_COMPLETE, response); handleSaveChangesComplete(combinedBlocksCount); } function handleSaveAllChangesFault(response) { childScope.$broadcast(events.SAVE_ALL_CHANGES_FAULT, response); handleSaveChangesFault(combinedBlocksCount); } function handleSaveChangesComplete(eventCount) { eventCount = angular.isNumber(eventCount) ? eventCount : 1; finishSaving(eventCount); } function handleSaveChangesFault(eventCount) { eventCount = angular.isNumber(eventCount) ? eventCount : 1; finishSaving(eventCount); } function handleSaveChangesFaultContinue(eventCount) { eventCount = angular.isNumber(eventCount) ? eventCount : 1; savedEventsCount += eventCount; if (savedEventsCount >= editableBlockCount) { $scope.dataSaving = false; resetState(); } } function startSaving() { $scope.dataSaving = true; } function finishSaving(eventCount) { savedEventsCount += eventCount; if (savedEventsCount >= editableBlockCount) { $scope.dataSaving = false; resetState(); closeEditMode(); } } function resetState() { combinedChanges = {}; processedEventsCount = 0; combinedBlocksCount = 0; savedEventsCount = 0; } function updateRequiredFieldsLabelVisibility() { $scope.hasRequiredFields = hasRequiredFields(); } function hasRequiredFields() { return $element.find('div.editable-content-section__content .required').length; } function getElementId() { return $element[0].id; } function closeEditMode() { $scope.editMode = false; childScope.editMode = false; $scope.dataSaving = false; // notify parents $scope.$emit(events.EDIT_COMPLETE, getElementId()); } $scope.$on('$destroy', function () { transcludedContent.remove(); childScope.$destroy(); }); $scope.$on(events.CLOSE_EDIT_MODE_ON_STATUS_CLOSED_FROM_BLADE, function (event, updatedTicket) { if (updatedTicket && !updatedTicket.detailsEditAllowed) { $scope.onCancelClick(); } }); }] }; }); })();