Changed editorContext to use appState instead for content/media/member editors - the appState saved is the basic entity, this means that if property editors resolve this value they do not have access to actually change the real content model which we don't want to allow (or changing other property's values).

Fixed up some inconsistencies between all of these editors and the content editor helper, fixed up tree syncing with the members editor.
This commit is contained in:
Shannon
2013-11-15 10:38:36 +11:00
parent 1c742db414
commit 5314afb51a
7 changed files with 72 additions and 43 deletions

View File

@@ -16,7 +16,8 @@ function appState($rootScope) {
touchDevice: null,
showTray: null,
stickyNavigation: null,
navMode: null
navMode: null,
editingEntity: null
};
var sectionState = {

View File

@@ -2,11 +2,13 @@
/**
* @ngdoc service
* @name umbraco.services.contentEditingHelper
* @description A helper service for content/media/member controllers when editing/creating/saving content.
* @description A helper service for most editors, some methods are specific to content/media/member model types but most are used by
* all editors to share logic and reduce the amount of replicated code among editors.
**/
function contentEditingHelper($location, $routeParams, notificationsService, serverValidationManager, dialogService, formHelper) {
function contentEditingHelper($location, $routeParams, notificationsService, serverValidationManager, dialogService, formHelper, appState) {
return {
/**
* @ngdoc method
@@ -36,15 +38,15 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser
* @function
*
* @description
* re-binds all changed property values to the origContent object from the newContent object and returns an array of changed properties.
* re-binds all changed property values to the origContent object from the savedContent object and returns an array of changed properties.
*/
reBindChangedProperties: function (origContent, newContent) {
reBindChangedProperties: function (origContent, savedContent) {
var changed = [];
//get a list of properties since they are contained in tabs
var allOrigProps = this.getAllProps(origContent);
var allNewProps = this.getAllProps(newContent);
var allNewProps = this.getAllProps(savedContent);
function getNewProp(alias) {
return _.find(allNewProps, function (item) {
@@ -66,8 +68,8 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser
continue;
}
if (!_.isEqual(origContent[o], newContent[o])) {
origContent[o] = newContent[o];
if (!_.isEqual(origContent[o], savedContent[o])) {
origContent[o] = savedContent[o];
}
}
@@ -109,9 +111,6 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser
if (!args.err) {
throw "args.err cannot be null";
}
if (!args.allNewProps && !angular.isArray(args.allNewProps)) {
throw "args.allNewProps must be a valid array";
}
if (args.redirectOnFailure === undefined || args.redirectOnFailure === null) {
throw "args.redirectOnFailure must be set to true or false";
}
@@ -168,11 +167,11 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser
if (!args) {
throw "args cannot be null";
}
if (!args.newContent) {
throw "args.newContent cannot be null";
if (!args.savedContent) {
throw "args.savedContent cannot be null";
}
if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.newContent.id)) {
if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.savedContent.id)) {
//we are not redirecting because this is not new content, it is existing content. In this case
// we need to detect what properties have changed and re-bind them with the server data.

View File

@@ -1,2 +0,0 @@
angular.module("umbraco.services")
.value('editorContext', undefined);

View File

@@ -6,7 +6,7 @@
* @description
* The controller for the content editor
*/
function ContentEditController($scope, $routeParams, $q, $timeout, $window, appState, contentResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, editorContext, treeService, fileManager, formHelper, umbRequestHelper, keyboardService) {
function ContentEditController($scope, $routeParams, $q, $timeout, $window, appState, contentResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, keyboardService, umbModelMapper) {
//setup scope vars
$scope.defaultButton = null;
@@ -15,9 +15,6 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
$scope.currentSection = appState.getSectionState("currentSection");
$scope.currentNode = null; //the editors affiliated node
//we need this to share our content object with property editors
editorContext = $scope.content;
//This sets up the action buttons based on what permissions the user has.
//The allowedActions parameter contains a list of chars, each represents a button by permission so
//here we'll build the buttons according to the chars of the user.
@@ -123,11 +120,15 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
savedContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
//update appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
configureButtons(data);
navigationService.syncTree({ tree: "content", path: data.path.split(","), forceReload: true }).then(function (syncArgs) {
$scope.currentNode = syncArgs.node;
});
@@ -139,10 +140,12 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
contentEditingHelper.handleSaveError({
redirectOnFailure: true,
err: err,
allNewProps: contentEditingHelper.getAllProps(err.data),
allOrigProps: contentEditingHelper.getAllProps($scope.content)
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
});
//update appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
deferred.reject(err);
});
}
@@ -159,6 +162,8 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
//put this into appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
configureButtons($scope.content);
});
}
@@ -168,6 +173,8 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
//put this into appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
configureButtons($scope.content);
//in one particular special case, after we've created a new item we redirect back to the edit
@@ -194,7 +201,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
savedContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});

View File

@@ -45,8 +45,8 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
$scope.preValues = [];
if ($routeParams.create) {
//we are creating so get an empty content item
dataTypeResource.getScaffold($routeParams.id, $routeParams.doctype)
//we are creating so get an empty data type item
dataTypeResource.getScaffold($routeParams.id)
.then(function(data) {
$scope.loaded = true;
$scope.preValuesLoaded = true;
@@ -101,7 +101,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
savedContent: data,
rebindCallback: function() {
createPreValueProps(data.preValues);
}
@@ -117,9 +117,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
// to be the same thing since that only really matters for content/media.
contentEditingHelper.handleSaveError({
redirectOnFailure: false,
err: err,
allNewProps: $scope.preValues,
allOrigProps: $scope.preValues
err: err
});
});
}

View File

@@ -6,7 +6,7 @@
* @description
* The controller for the media editor
*/
function mediaEditController($scope, $routeParams, appState, mediaResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, treeService, formHelper) {
function mediaEditController($scope, $routeParams, appState, mediaResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, treeService, formHelper, umbModelMapper) {
//setup scope vars
$scope.nav = navigationService;
@@ -19,7 +19,8 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, navi
.then(function (data) {
$scope.loaded = true;
$scope.content = data;
//put this into appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
});
}
else {
@@ -27,7 +28,9 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, navi
.then(function (data) {
$scope.loaded = true;
$scope.content = data;
//put this into appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
//in one particular special case, after we've created a new item we redirect back to the edit
// route but there might be server validation errors in the collection which we need to display
// after the redirect, so we will bind all subscriptions which will show the server validation errors
@@ -52,10 +55,13 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, navi
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
savedContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
//update appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
navigationService.syncTree({ tree: "media", path: data.path, forceReload: true }).then(function (syncArgs) {
$scope.currentNode = syncArgs.node;
});
@@ -65,9 +71,11 @@ function mediaEditController($scope, $routeParams, appState, mediaResource, navi
contentEditingHelper.handleSaveError({
err: err,
redirectOnFailure: true,
allNewProps: contentEditingHelper.getAllProps(err.data),
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
});
//update appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
});
}

View File

@@ -6,19 +6,29 @@
* @description
* The controller for the member editor
*/
function MemberEditController($scope, $routeParams, $location, $q, $window, appState, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, treeService) {
function MemberEditController($scope, $routeParams, $location, $q, $window, appState, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, umbModelMapper) {
//setup scope vars
$scope.nav = navigationService;
$scope.currentSection = appState.getSectionState("currentSection");
$scope.currentNode = null; //the editors affiliated node
//build a path to sync the tree with
function buildTreePath(data) {
//TODO: Will this work for the 'other' list ?
var path = data.name[0] + "," + data.key;
path = path.replace(/-/g, '');
return path;
}
if ($routeParams.create) {
//we are creating so get an empty member item
memberResource.getScaffold($routeParams.doctype)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
//put this into appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
});
}
else {
@@ -40,9 +50,10 @@ function MemberEditController($scope, $routeParams, $location, $q, $window, appS
$scope.loaded = true;
$scope.content = data;
//build a path to sync the tree with
var path = data.name[0]+"," + data.key;
path = path.replace(/-/g,'');
//put this into appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
var path = buildTreePath(data);
navigationService.syncTree({ tree: "member", path: path.split(",") }).then(function (syncArgs) {
$scope.currentNode = syncArgs.node;
@@ -69,13 +80,18 @@ function MemberEditController($scope, $routeParams, $location, $q, $window, appS
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
savedContent: data,
//specify a custom id to redirect to since we want to use the GUID
redirectId: data.key,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
navigationService.syncTree({ tree: "member", path: path.split(",") }).then(function (syncArgs) {
//update appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
var path = buildTreePath(data);
navigationService.syncTree({ tree: "member", path: path.split(","), forceReload: true }).then(function (syncArgs) {
$scope.currentNode = syncArgs.node;
});
@@ -84,9 +100,11 @@ function MemberEditController($scope, $routeParams, $location, $q, $window, appS
contentEditingHelper.handleSaveError({
redirectOnFailure: false,
err: err,
allNewProps: contentEditingHelper.getAllProps(err.data),
allOrigProps: contentEditingHelper.getAllProps($scope.content)
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
});
//update appState
appState.setGlobalState("editingEntity", umbModelMapper.convertToEntityBasic($scope.content));
});
}