Merge pull request #996 from umbraco/temp-U4-7593

fixes: U4-7593 Removing a composite from an existing doctype - Need b…
This commit is contained in:
Shannon Deminick
2016-01-11 17:15:17 +01:00
7 changed files with 298 additions and 204 deletions

View File

@@ -11,6 +11,10 @@
function link(scope, el, attr, ctrl) {
scope.directive = {
enableConfirmButton: false
};
var overlayNumber = 0;
var numberOfOverlays = 0;
var isRegistered = false;
@@ -222,21 +226,23 @@
}
scope.submitForm = function(model) {
if(scope.model.submit) {
if (formHelper.submitForm({scope: scope})) {
formHelper.resetForm({ scope: scope });
if (formHelper.submitForm({scope: scope})) {
if(scope.model.confirmSubmit && scope.model.confirmSubmit.enable && !scope.directive.enableConfirmButton) {
scope.model.submit(model, modelCopy, scope.directive.enableConfirmButton);
} else {
unregisterOverlay();
scope.model.submit(model, modelCopy, scope.directive.enableConfirmButton);
}
formHelper.resetForm({ scope: scope });
unregisterOverlay();
scope.model.submit(model);
}
}
}
}
};
scope.cancelConfirmSubmit = function() {
scope.model.confirmSubmit.show = false;
};
scope.closeOverLay = function() {

View File

@@ -151,64 +151,95 @@
};
scope.openCompositionsDialog = function() {
scope.compositionsDialogModel = {};
scope.compositionsDialogModel.title = "Compositions";
scope.compositionsDialogModel.contentType = scope.model;
scope.compositionsDialogModel.availableCompositeContentTypes = scope.model.availableCompositeContentTypes;
scope.compositionsDialogModel.compositeContentTypes = scope.model.compositeContentTypes;
scope.compositionsDialogModel.view = "views/common/overlays/contenttypeeditor/compositions/compositions.html";
scope.compositionsDialogModel.show = true;
scope.compositionsDialogModel.submit = function(model) {
scope.compositionsDialogModel = {
title: "Compositions",
contentType: scope.model,
availableCompositeContentTypes: scope.model.availableCompositeContentTypes,
compositeContentTypes: scope.model.compositeContentTypes,
view: "views/common/overlays/contenttypeeditor/compositions/compositions.html",
confirmSubmit: {
title: "Warning",
description: "Removing a composition will delete all the associated property data. Once you save the document type there's no way back, are you sure?",
checkboxLabel: "I know what I'm doing",
enable: true
},
show: true,
submit: function(model, oldModel, confirmed) {
// make sure that all tabs has an init property
if (scope.model.groups.length !== 0) {
angular.forEach(scope.model.groups, function(group) {
addInitProperty(group);
});
}
var compositionRemoved = false;
// remove overlay
scope.compositionsDialogModel.show = false;
scope.compositionsDialogModel = null;
};
// check if any compositions has been removed
for(var i = 0; oldModel.compositeContentTypes.length > i; i++) {
scope.compositionsDialogModel.close = function(oldModel) {
// reset composition changes
scope.model.groups = oldModel.contentType.groups;
scope.model.compositeContentTypes = oldModel.contentType.compositeContentTypes;
var oldComposition = oldModel.compositeContentTypes[i];
// remove overlay
scope.compositionsDialogModel.show = false;
scope.compositionsDialogModel = null;
};
if(_.contains(model.compositeContentTypes, oldComposition) === false) {
compositionRemoved = true;
}
scope.compositionsDialogModel.selectCompositeContentType = function(compositeContentType) {
}
if (scope.model.compositeContentTypes.indexOf(compositeContentType.alias) === -1) {
//merge composition with content type
// show overlay confirm box if compositions has been removed.
if(compositionRemoved && confirmed === false) {
if(scope.contentType === "documentType") {
scope.compositionsDialogModel.confirmSubmit.show = true;
contentTypeResource.getById(compositeContentType.id).then(function(composition){
contentTypeHelper.mergeCompositeContentType(scope.model, composition);
});
// submit overlay if no compositions has been removed
// or the action has been confirmed
} else {
// make sure that all tabs has an init property
if (scope.model.groups.length !== 0) {
angular.forEach(scope.model.groups, function(group) {
addInitProperty(group);
});
}
// remove overlay
scope.compositionsDialogModel.show = false;
scope.compositionsDialogModel = null;
}
},
close: function(oldModel) {
// reset composition changes
scope.model.groups = oldModel.contentType.groups;
scope.model.compositeContentTypes = oldModel.contentType.compositeContentTypes;
// remove overlay
scope.compositionsDialogModel.show = false;
scope.compositionsDialogModel = null;
},
selectCompositeContentType: function(compositeContentType) {
if (scope.model.compositeContentTypes.indexOf(compositeContentType.alias) === -1) {
//merge composition with content type
if(scope.contentType === "documentType") {
contentTypeResource.getById(compositeContentType.id).then(function(composition){
contentTypeHelper.mergeCompositeContentType(scope.model, composition);
});
} else if(scope.contentType === "mediaType") {
} else if(scope.contentType === "mediaType") {
mediaTypeResource.getById(compositeContentType.id).then(function(composition){
contentTypeHelper.mergeCompositeContentType(scope.model, composition);
});
mediaTypeResource.getById(compositeContentType.id).then(function(composition){
contentTypeHelper.mergeCompositeContentType(scope.model, composition);
});
}
} else {
// split composition from content type
contentTypeHelper.splitCompositeContentType(scope.model, compositeContentType);
}
}
} else {
// split composition from content type
contentTypeHelper.splitCompositeContentType(scope.model, compositeContentType);
}
};
};

View File

@@ -7,11 +7,20 @@
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
}
.umb-overlay__form {
display: flex;
flex-wrap: nowrap;
flex-direction: column;
height: 100%;
}
.umb-overlay .umb-overlay-header {
background: @grayLighter;
border-bottom: 1px solid @grayLight;
padding: 10px;
margin-top: 0;
flex-grow: 0;
flex-shrink: 0;
}
@@ -29,29 +38,31 @@
}
.umb-overlay .umb-overlay-container {
top: 50px;
left: 7px;
right: 7px;
bottom: 7px;
position: absolute;
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
overflow-y: auto;
overflow-x: hidden;
position: relative;
height: auto;
}
.umb-overlay .umb-overlay-drawer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 31px;
padding: 10px;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 31px;
padding: 10px 20px;
margin: 0;
background: @grayLighter;
border-top: 1px solid @grayLight;
}
.umb-overlay .umb-overlay-drawer .umb-overlay-drawer-content {
.umb-overlay .umb-overlay-drawer.-auto-height {
flex-basis: auto;
}
.umb-overlay .umb-overlay-drawer .umb-overlay-drawer__align-right {
display: flex;
justify-content: flex-end;
}
@@ -76,7 +87,6 @@
}
.umb-overlay.umb-overlay-center .umb-overlay-container {
top: 68px;
padding: 20px;
}
@@ -92,8 +102,7 @@
}
.umb-overlay.umb-overlay-target .umb-overlay-container {
top: 68px;
bottom: 58px;
padding: 10px;
}
/* ---------- OVERLAY RIGHT ---------- */
@@ -107,16 +116,12 @@
}
.umb-overlay.umb-overlay-right .umb-overlay-header {
height: 100px;
flex-basis: 100px;
padding: 20px;
box-sizing: border-box;
}
.umb-overlay.umb-overlay-right .umb-overlay-container {
top: 100px;
left: 0;
right: 0;
bottom: 52px;
padding: 20px;
}
@@ -132,16 +137,12 @@
}
.umb-overlay.umb-overlay-left .umb-overlay-header {
height: 100px;
flex-basis: 100px;
padding: 20px;
box-sizing: border-box;
}
.umb-overlay.umb-overlay-left .umb-overlay-container {
top: 100px;
left: 0;
right: 0;
bottom: 51px;
padding: 20px;
}

View File

@@ -1,5 +1,5 @@
<div class="umb-overlay umb-overlay-{{position}}" on-outside-click="closeOverLay()">
<form name="overlayForm" ng-submit="submitForm(model)" novalidate val-form-manager>
<form class="umb-overlay__form" name="overlayForm" ng-submit="submitForm(model)" novalidate val-form-manager>
<div class="umb-overlay-header">
<h4 class="umb-overlay__title">{{model.title}}</h4>
@@ -21,11 +21,53 @@
</div>
<div class="umb-overlay-drawer">
<div class="umb-overlay-drawer-content">
<umb-button action="closeOverLay()" button-style="link" label-key="{{model.closeButtonLabelKey}}" label="{{model.closeButtonLabel}}" type="button"></umb-button>
<umb-button button-style="success" label-key="{{model.submitButtonLabelKey}}" label="{{model.submitButtonLabel}}" ng-if="model.submit && model.hideSubmitButton !== true" type="submit"></umb-button>
<div class="umb-overlay-drawer" ng-class="{'-auto-height': model.confirmSubmit.show}">
<div ng-if="model.confirmSubmit.show">
<h5 class="red" ng-if="model.confirmSubmit.title"><i class="icon-alert"></i> {{ model.confirmSubmit.title }}</h5>
<p ng-if="model.confirmSubmit.description">{{ model.confirmSubmit.description }}</p>
<label class="checkbox no-indent">
<input type="checkbox" ng-model="directive.enableConfirmButton" />
<strong>{{model.confirmSubmit.checkboxLabel}}</strong>
</label>
<div class="umb-overlay-drawer__align-right">
<umb-button
action="cancelConfirmSubmit()"
button-style="link"
label="Cancel"
type="button">
</umb-button>
<umb-button
button-style="success"
label="Confirm"
type="submit"
disabled="!directive.enableConfirmButton">
</umb-button>
</div>
</div>
<div class="umb-overlay-drawer__align-right" ng-if="!model.confirmSubmit.show">
<umb-button
action="closeOverLay()"
button-style="link"
label-key="{{model.closeButtonLabelKey}}"
label="{{model.closeButtonLabel}}"
type="button">
</umb-button>
<umb-button
button-style="success"
label-key="{{model.submitButtonLabelKey}}"
label="{{model.submitButtonLabel}}"
ng-if="model.submit && model.hideSubmitButton !== true"
type="submit">
</umb-button>
</div>
</div>
</form>
</div>

View File

@@ -8,8 +8,8 @@
*/
(function () {
"use strict";
function DocumentTypesEditController($scope, $routeParams, modelsResource, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService) {
function DocumentTypesEditController($scope, $routeParams, modelsResource, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper) {
var vm = this;
@@ -139,75 +139,81 @@
/* ---------- SAVE ---------- */
function save() {
var deferred = $q.defer();
vm.page.saveButtonState = "busy";
// only save if there is no overlays open
if(overlayHelper.getNumberOfOverlays() === 0) {
// reformat allowed content types to array if id's
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
var deferred = $q.defer();
contentEditingHelper.contentEditorPerformSave({
statusMessage: "Saving...",
saveMethod: contentTypeResource.save,
scope: $scope,
content: vm.contentType,
// we need to rebind... the IDs that have been created!
rebindCallback: function (origContentType, savedContentType) {
vm.contentType.id = savedContentType.id;
vm.contentType.groups.forEach(function(group) {
if (!group.name) return;
vm.page.saveButtonState = "busy";
var k = 0;
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
k++;
if (k == savedContentType.groups.length) {
group.id = 0;
return;
}
// reformat allowed content types to array if id's
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
var savedGroup = savedContentType.groups[k];
if (!group.id) group.id = savedGroup.id;
contentEditingHelper.contentEditorPerformSave({
statusMessage: "Saving...",
saveMethod: contentTypeResource.save,
scope: $scope,
content: vm.contentType,
// we need to rebind... the IDs that have been created!
rebindCallback: function (origContentType, savedContentType) {
vm.contentType.id = savedContentType.id;
vm.contentType.groups.forEach(function(group) {
if (!group.name) return;
group.properties.forEach(function (property) {
if (property.id || !property.alias) return;
k = 0;
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
var k = 0;
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
k++;
if (k == savedGroup.properties.length) {
property.id = 0;
if (k == savedContentType.groups.length) {
group.id = 0;
return;
}
var savedProperty = savedGroup.properties[k];
property.id = savedProperty.id;
var savedGroup = savedContentType.groups[k];
if (!group.id) group.id = savedGroup.id;
group.properties.forEach(function (property) {
if (property.id || !property.alias) return;
k = 0;
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
k++;
if (k == savedGroup.properties.length) {
property.id = 0;
return;
}
var savedProperty = savedGroup.properties[k];
property.id = savedProperty.id;
});
});
});
}
}).then(function (data) {
//success
syncTreeNode(vm.contentType, data.path);
}
}).then(function (data) {
//success
syncTreeNode(vm.contentType, data.path);
vm.page.saveButtonState = "success";
vm.page.saveButtonState = "success";
deferred.resolve(data);
}, function (err) {
//error
if (err) {
editorState.set($scope.content);
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
notificationsService.error(headerValue, msgValue);
deferred.resolve(data);
}, function (err) {
//error
if (err) {
editorState.set($scope.content);
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
notificationsService.error(headerValue, msgValue);
});
});
});
}
vm.page.saveButtonState = "error";
}
vm.page.saveButtonState = "error";
deferred.reject(err);
});
return deferred.promise;
deferred.reject(err);
});
return deferred.promise;
}
}

View File

@@ -9,7 +9,7 @@
(function () {
"use strict";
function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService) {
function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper) {
var vm = this;
vm.save = save;
@@ -120,46 +120,51 @@
/* ---------- SAVE ---------- */
function save() {
var deferred = $q.defer();
vm.page.saveButtonState = "busy";
// only save if there is no overlays open
if(overlayHelper.getNumberOfOverlays() === 0) {
// reformat allowed content types to array if id's
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
var deferred = $q.defer();
contentEditingHelper.contentEditorPerformSave({
statusMessage: "Saving...",
saveMethod: mediaTypeResource.save,
scope: $scope,
content: vm.contentType,
//no-op for rebind callback... we don't really need to rebind for content types
rebindCallback: angular.noop
}).then(function (data) {
//success
syncTreeNode(vm.contentType, data.path);
vm.page.saveButtonState = "busy";
vm.page.saveButtonState = "success";
// reformat allowed content types to array if id's
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
deferred.resolve(data);
}, function (err) {
//error
if (err) {
editorState.set($scope.content);
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
notificationsService.error(headerValue, msgValue);
contentEditingHelper.contentEditorPerformSave({
statusMessage: "Saving...",
saveMethod: mediaTypeResource.save,
scope: $scope,
content: vm.contentType,
//no-op for rebind callback... we don't really need to rebind for content types
rebindCallback: angular.noop
}).then(function (data) {
//success
syncTreeNode(vm.contentType, data.path);
vm.page.saveButtonState = "success";
deferred.resolve(data);
}, function (err) {
//error
if (err) {
editorState.set($scope.content);
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
notificationsService.error(headerValue, msgValue);
});
});
});
}
}
vm.page.saveButtonState = "error";
vm.page.saveButtonState = "error";
deferred.reject(err);
});
deferred.reject(err);
});
return deferred.promise;
return deferred.promise;
}
}
function init(contentType) {

View File

@@ -9,7 +9,7 @@
(function () {
"use strict";
function MemberTypesEditController($scope, $rootScope, $routeParams, $log, $filter, memberTypeResource, dataTypeResource, editorState, iconHelper, formHelper, navigationService, contentEditingHelper, notificationsService, $q, localizationService) {
function MemberTypesEditController($scope, $rootScope, $routeParams, $log, $filter, memberTypeResource, dataTypeResource, editorState, iconHelper, formHelper, navigationService, contentEditingHelper, notificationsService, $q, localizationService, overlayHelper) {
var vm = this;
@@ -78,44 +78,47 @@
}
function save() {
// only save if there is no overlays open
if(overlayHelper.getNumberOfOverlays() === 0) {
var deferred = $q.defer();
var deferred = $q.defer();
vm.page.saveButtonState = "busy";
contentEditingHelper.contentEditorPerformSave({
statusMessage: "Saving...",
saveMethod: memberTypeResource.save,
scope: $scope,
content: vm.contentType,
//no-op for rebind callback... we don't really need to rebind for content types
rebindCallback: angular.noop
}).then(function (data) {
//success
syncTreeNode(vm.contentType, data.path);
vm.page.saveButtonState = "busy";
vm.page.saveButtonState = "success";
contentEditingHelper.contentEditorPerformSave({
statusMessage: "Saving...",
saveMethod: memberTypeResource.save,
scope: $scope,
content: vm.contentType,
//no-op for rebind callback... we don't really need to rebind for content types
rebindCallback: angular.noop
}).then(function (data) {
//success
syncTreeNode(vm.contentType, data.path);
deferred.resolve(data);
}, function (err) {
//error
if (err) {
editorState.set($scope.content);
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
notificationsService.error(headerValue, msgValue);
vm.page.saveButtonState = "success";
deferred.resolve(data);
}, function (err) {
//error
if (err) {
editorState.set($scope.content);
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
notificationsService.error(headerValue, msgValue);
});
});
});
}
}
vm.page.saveButtonState = "error";
vm.page.saveButtonState = "error";
deferred.reject(err);
});
deferred.reject(err);
});
return deferred.promise;
return deferred.promise;
}
}