diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js
index 7d6d5dc131..4902d943a7 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbvariantcontenteditors.directive.js
@@ -179,6 +179,15 @@
variant.variants[i].active = false;
}
}
+
+ // keep track of the open variants across the different split views
+ // push the first variant then update the variant index based on the editor index
+ if(vm.openVariants && vm.openVariants.length === 0) {
+ vm.openVariants.push(variant.language.culture);
+ } else {
+ vm.openVariants[editorIndex] = variant.language.culture;
+ }
+
}
//then assign the variant to a view model to the content app
@@ -186,14 +195,6 @@
return a.alias === "content";
});
contentApp.viewModel = variant;
-
- // keep track of the open variants across the different split views
- // push the first variant then update the variant index based on the editor index
- if(vm.openVariants && vm.openVariants.length === 0) {
- vm.openVariants.push(variant.language.culture);
- } else {
- vm.openVariants[editorIndex] = variant.language.culture;
- }
// make sure the same app it set to active in the new variant
if(activeAppAlias) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
index 3ad2864fa8..ffcf9f2eef 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
@@ -204,6 +204,29 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q
});
},
+ /**
+ * @ngdoc method
+ * @name umbraco.services.navigationService#retainQueryStrings
+ * @methodOf umbraco.services.navigationService
+ *
+ * @description
+ * Will check the next route parameters to see if any of the query strings that should be retained from the previous route are missing,
+ * if they are they will be merged and an object containing all route parameters is returned. If nothing should be changed, then null is returned.
+ * @param {Object} currRouteParams The current route parameters
+ * @param {Object} nextRouteParams The next route parameters
+ */
+ retainQueryStrings: function (currRouteParams, nextRouteParams) {
+ var toRetain = angular.copy(nextRouteParams);
+ var updated = false;
+ _.each(retainedQueryStrings, function (r) {
+ if (currRouteParams[r] && !nextRouteParams[r]) {
+ toRetain[r] = currRouteParams[r];
+ updated = true;
+ }
+ });
+ return updated ? toRetain : null;
+ },
+
/**
* @ngdoc method
* @name umbraco.services.navigationService#load
diff --git a/src/Umbraco.Web.UI.Client/src/init.js b/src/Umbraco.Web.UI.Client/src/init.js
index 50e5c21203..3f44638096 100644
--- a/src/Umbraco.Web.UI.Client/src/init.js
+++ b/src/Umbraco.Web.UI.Client/src/init.js
@@ -122,12 +122,25 @@ app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlH
$route.reload();
}
else {
- //check if the location being changed is only the mculture query string, if so, cancel the routing since this is just
- //used as a global persistent query string that does not change routes.
-
+
+ //check if the location being changed is only due to global/state query strings which means the location change
+ //isn't actually going to cause a route change.
if (navigationService.isRouteChangingNavigation(currentRouteParams, next.params)) {
- //continue the route
- $route.reload();
+ //The location change will cause a route change. We need to ensure that the global/state
+ //query strings have not been stripped out. If they have, we'll re-add them and re-route.
+
+ var toRetain = navigationService.retainQueryStrings(currentRouteParams, next.params);
+ if (toRetain) {
+ $route.updateParams(toRetain);
+ }
+ else {
+ //continue the route
+ $route.reload();
+ }
+ }
+ else {
+ //navigation is not changing but we should update the currentRouteParams to include all current parameters
+ currentRouteParams = angular.copy(next.params);
}
}
});
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less
index 15a319b520..b0c90483f7 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less
@@ -36,7 +36,7 @@
}
.umb-content-grid__icon.-light {
- color: @gray-8;
+ color: @gray-5;
}
@@ -58,7 +58,7 @@
}
.umb-content-grid__item-name.-light {
- color: @gray-8;
+ color: @gray-5;
}
.umb-content-grid__details-list {
@@ -69,7 +69,7 @@
}
.umb-content-grid__details-list.-light {
- color: @gray-8;
+ color: @gray-5;
}
.umb-content-grid__details-label {
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html
index 33be361206..760597fcab 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html
@@ -15,12 +15,16 @@
{{ item.name }}
-
- -
-
{{ property.header }}:
- {{ item[property.alias] }}
-
-
+
+ -
+
:
+
+
+ -
+
{{ property.header }}:
+ {{ item[property.alias] }}
+
+
@@ -32,4 +36,4 @@
There are no items to show
-
\ No newline at end of file
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html
index 5245384aac..91c0af5005 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html
@@ -15,6 +15,9 @@
+
+ Status
+
+
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js
index 5f38f7daae..e1a1299c55 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js
@@ -1,167 +1,175 @@
-function listViewController($scope, $routeParams, $injector, $location, $timeout, currentUserResource, notificationsService, iconHelper, editorState, localizationService, appState, mediaResource, listViewHelper, navigationService, editorService) {
+function listViewController($scope, $routeParams, $injector, $timeout, currentUserResource, notificationsService, iconHelper, editorState, localizationService, appState, mediaResource, listViewHelper, navigationService, editorService) {
- //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content
- // that isn't created yet, if we continue this will use the parent id in the route params which isn't what
- // we want. NOTE: This is just a safety check since when we scaffold an empty model on the server we remove
- // the list view tab entirely when it's new.
- if ($routeParams.create) {
- $scope.isNew = true;
- return;
- }
+ //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content
+ // that isn't created yet, if we continue this will use the parent id in the route params which isn't what
+ // we want. NOTE: This is just a safety check since when we scaffold an empty model on the server we remove
+ // the list view tab entirely when it's new.
+ if ($routeParams.create) {
+ $scope.isNew = true;
+ return;
+ }
- //Now we need to check if this is for media, members or content because that will depend on the resources we use
- var contentResource, getContentTypesCallback, getListResultsCallback, deleteItemCallback, getIdCallback, createEditUrlCallback;
+ //Now we need to check if this is for media, members or content because that will depend on the resources we use
+ var contentResource, getContentTypesCallback, getListResultsCallback, deleteItemCallback, getIdCallback, createEditUrlCallback;
- //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals)
- if (($scope.model.config.entityType && $scope.model.config.entityType === "member") || (appState.getSectionState("currentSection") === "member")) {
- $scope.entityType = "member";
- contentResource = $injector.get('memberResource');
- getContentTypesCallback = $injector.get('memberTypeResource').getTypes;
- getListResultsCallback = contentResource.getPagedResults;
- deleteItemCallback = contentResource.deleteByKey;
- getIdCallback = function (selected) {
- return selected.key;
- };
- createEditUrlCallback = function (item) {
- return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.key + "?page=" + $scope.options.pageNumber + "&listName=" + $scope.contentId;
- };
- }
- else {
- //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals)
- if (($scope.model.config.entityType && $scope.model.config.entityType === "media") || (appState.getSectionState("currentSection") === "media")) {
- $scope.entityType = "media";
- contentResource = $injector.get('mediaResource');
- getContentTypesCallback = $injector.get('mediaTypeResource').getAllowedTypes;
- }
- else {
- $scope.entityType = "content";
- contentResource = $injector.get('contentResource');
- getContentTypesCallback = $injector.get('contentTypeResource').getAllowedTypes;
- }
- getListResultsCallback = contentResource.getChildren;
- deleteItemCallback = contentResource.deleteById;
- getIdCallback = function (selected) {
- return selected.id;
- };
- createEditUrlCallback = function (item) {
- return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.id + "?page=" + $scope.options.pageNumber;
- };
- }
+ //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals)
+ if (($scope.model.config.entityType && $scope.model.config.entityType === "member") || (appState.getSectionState("currentSection") === "member")) {
+ $scope.entityType = "member";
+ contentResource = $injector.get('memberResource');
+ getContentTypesCallback = $injector.get('memberTypeResource').getTypes;
+ getListResultsCallback = contentResource.getPagedResults;
+ deleteItemCallback = contentResource.deleteByKey;
+ getIdCallback = function (selected) {
+ return selected.key;
+ };
+ createEditUrlCallback = function (item) {
+ return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.key + "?page=" + $scope.options.pageNumber + "&listName=" + $scope.contentId;
+ };
+ }
+ else {
+ //check the config for the entity type, or the current section name (since the config is only set in c#, not in pre-vals)
+ if (($scope.model.config.entityType && $scope.model.config.entityType === "media") || (appState.getSectionState("currentSection") === "media")) {
+ $scope.entityType = "media";
+ contentResource = $injector.get('mediaResource');
+ getContentTypesCallback = $injector.get('mediaTypeResource').getAllowedTypes;
+ }
+ else {
+ $scope.entityType = "content";
+ contentResource = $injector.get('contentResource');
+ getContentTypesCallback = $injector.get('contentTypeResource').getAllowedTypes;
+ }
+ getListResultsCallback = contentResource.getChildren;
+ deleteItemCallback = contentResource.deleteById;
+ getIdCallback = function (selected) {
+ return selected.id;
+ };
+ createEditUrlCallback = function (item) {
+ return "/" + $scope.entityType + "/" + $scope.entityType + "/edit/" + item.id + "?page=" + $scope.options.pageNumber;
+ };
+ }
- $scope.pagination = [];
- $scope.isNew = false;
- $scope.actionInProgress = false;
- $scope.selection = [];
- $scope.folders = [];
- $scope.page = {};
- $scope.listViewResultSet = {
- totalPages: 0,
- items: []
- };
+ $scope.pagination = [];
+ $scope.isNew = false;
+ $scope.actionInProgress = false;
+ $scope.selection = [];
+ $scope.folders = [];
+ $scope.page = {};
+ $scope.listViewResultSet = {
+ totalPages: 0,
+ items: []
+ };
- //when this is null, we don't check permissions
- $scope.currentNodePermissions = null;
+ //when this is null, we don't check permissions
+ $scope.currentNodePermissions = null;
- if ($scope.entityType === "content") {
- //Just ensure we do have an editorState
- if (editorState.current) {
- //Fetch current node allowed actions for the current user
- //This is the current node & not each individual child node in the list
- var currentUserPermissions = editorState.current.allowedActions;
+ if ($scope.entityType === "content") {
+ //Just ensure we do have an editorState
+ if (editorState.current) {
+ //Fetch current node allowed actions for the current user
+ //This is the current node & not each individual child node in the list
+ var currentUserPermissions = editorState.current.allowedActions;
- //Create a nicer model rather than the funky & hard to remember permissions strings
- $scope.currentNodePermissions = {
- "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O
- "canCreate": _.contains(currentUserPermissions, 'C'), //Magic Char = C
- "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D
- "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M
- "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U
- "canUnpublish": _.contains(currentUserPermissions, 'U') //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
- };
- }
- }
+ //Create a nicer model rather than the funky & hard to remember permissions strings
+ $scope.currentNodePermissions = {
+ "canCopy": _.contains(currentUserPermissions, 'O'), //Magic Char = O
+ "canCreate": _.contains(currentUserPermissions, 'C'), //Magic Char = C
+ "canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D
+ "canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M
+ "canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U
+ "canUnpublish": _.contains(currentUserPermissions, 'U') //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
+ };
+ }
+ }
- //when this is null, we don't check permissions
- $scope.buttonPermissions = null;
+ //when this is null, we don't check permissions
+ $scope.buttonPermissions = null;
- //When we are dealing with 'content', we need to deal with permissions on child nodes.
- // Currently there is no real good way to
- if ($scope.entityType === "content") {
+ //When we are dealing with 'content', we need to deal with permissions on child nodes.
+ // Currently there is no real good way to
+ if ($scope.entityType === "content") {
- var idsWithPermissions = null;
+ var idsWithPermissions = null;
- $scope.buttonPermissions = {
- canCopy: true,
- canCreate: true,
- canDelete: true,
- canMove: true,
- canPublish: true,
- canUnpublish: true
- };
+ $scope.buttonPermissions = {
+ canCopy: true,
+ canCreate: true,
+ canDelete: true,
+ canMove: true,
+ canPublish: true,
+ canUnpublish: true
+ };
- $scope.$watch("selection.length", function (newVal, oldVal) {
+ $scope.$watch("selection.length", function (newVal, oldVal) {
- if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) {
+ if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) {
- //get all of the selected ids
- var ids = _.map($scope.selection, function (i) {
- return i.id.toString();
- });
+ //get all of the selected ids
+ var ids = _.map($scope.selection, function (i) {
+ return i.id.toString();
+ });
- //remove the dictionary items that don't have matching ids
- var filtered = {};
- _.each(idsWithPermissions, function (value, key, list) {
- if (_.contains(ids, key)) {
- filtered[key] = value;
- }
- });
- idsWithPermissions = filtered;
+ //remove the dictionary items that don't have matching ids
+ var filtered = {};
+ _.each(idsWithPermissions, function (value, key, list) {
+ if (_.contains(ids, key)) {
+ filtered[key] = value;
+ }
+ });
+ idsWithPermissions = filtered;
- //find all ids that we haven't looked up permissions for
- var existingIds = _.keys(idsWithPermissions);
- var missingLookup = _.map(_.difference(ids, existingIds), function (i) {
- return Number(i);
- });
+ //find all ids that we haven't looked up permissions for
+ var existingIds = _.keys(idsWithPermissions);
+ var missingLookup = _.map(_.difference(ids, existingIds), function (i) {
+ return Number(i);
+ });
- if (missingLookup.length > 0) {
- currentUserResource.getPermissions(missingLookup).then(function (p) {
- $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions);
- });
+ if (missingLookup.length > 0) {
+ currentUserResource.getPermissions(missingLookup).then(function (p) {
+ $scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions);
+ });
+ }
+ else {
+ $scope.buttonPermissions = listViewHelper.getButtonPermissions({}, idsWithPermissions);
+ }
}
- else {
- $scope.buttonPermissions = listViewHelper.getButtonPermissions({}, idsWithPermissions);
- }
- }
- });
+ });
- }
+ }
- //Get the current culturename from the QueryString - to pass into the WebAPI call
- var cultureNameQs = $location.search().cculture ? $location.search().cculture : $location.search().mculture;
+ $scope.options = {
+ displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1,
+ pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10,
+ pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1,
+ filter: '',
+ orderBy: ($scope.model.config.orderBy ? $scope.model.config.orderBy : 'VersionDate').trim(),
+ orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection.trim() : "desc",
+ orderBySystemField: true,
+ includeProperties: $scope.model.config.includeProperties ? $scope.model.config.includeProperties : [
+ { alias: 'updateDate', header: 'Last edited', isSystem: 1 },
+ { alias: 'updater', header: 'Last edited by', isSystem: 1 }
+ ],
+ layout: {
+ layouts: $scope.model.config.layouts,
+ activeLayout: listViewHelper.getLayout($routeParams.id, $scope.model.config.layouts)
+ },
+ allowBulkPublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkPublish,
+ allowBulkUnpublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkUnpublish,
+ allowBulkCopy: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkCopy,
+ allowBulkMove: $scope.model.config.bulkActionPermissions.allowBulkMove,
+ allowBulkDelete: $scope.model.config.bulkActionPermissions.allowBulkDelete,
+ cultureName: $routeParams.cculture ? $routeParams.cculture : $routeParams.mculture
+ };
- $scope.options = {
- displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1,
- pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10,
- pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1,
- filter: '',
- orderBy: ($scope.model.config.orderBy ? $scope.model.config.orderBy : 'VersionDate').trim(),
- orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection.trim() : "desc",
- orderBySystemField: true,
- includeProperties: $scope.model.config.includeProperties ? $scope.model.config.includeProperties : [
- { alias: 'updateDate', header: 'Last edited', isSystem: 1 },
- { alias: 'updater', header: 'Last edited by', isSystem: 1 }
- ],
- layout: {
- layouts: $scope.model.config.layouts,
- activeLayout: listViewHelper.getLayout($routeParams.id, $scope.model.config.layouts)
- },
- allowBulkPublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkPublish,
- allowBulkUnpublish: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkUnpublish,
- allowBulkCopy: $scope.entityType === 'content' && $scope.model.config.bulkActionPermissions.allowBulkCopy,
- allowBulkMove: $scope.model.config.bulkActionPermissions.allowBulkMove,
- allowBulkDelete: $scope.model.config.bulkActionPermissions.allowBulkDelete,
- cultureName: cultureNameQs
- };
+ //watch for culture changes in the query strings and update accordingly
+ $scope.$watch(function () {
+ return $routeParams.cculture ? $routeParams.cculture : $routeParams.mculture;
+ }, function (newVal, oldVal) {
+ if (newVal && newVal !== oldVal) {
+ //update the options
+ $scope.options.cultureName = newVal;
+ $scope.reloadView($scope.contentId);
+ }
+ });
// Check if selected order by field is actually custom field
for (var j = 0; j < $scope.options.includeProperties.length; j++) {
@@ -172,8 +180,8 @@ function listViewController($scope, $routeParams, $injector, $location, $timeout
}
}
- //update all of the system includeProperties to enable sorting
- _.each($scope.options.includeProperties, function (e, i) {
+ //update all of the system includeProperties to enable sorting
+ _.each($scope.options.includeProperties, function (e, i) {
//NOTE: special case for contentTypeAlias, it's a system property that cannot be sorted
// to do that, we'd need to update the base query for content to include the content type alias column
@@ -194,11 +202,11 @@ function listViewController($scope, $routeParams, $injector, $location, $timeout
e.header = v;
});
}
- });
+ });
- $scope.selectLayout = function (selectedLayout) {
- $scope.options.layout.activeLayout = listViewHelper.setLayout($routeParams.id, selectedLayout, $scope.model.config.layouts);
- };
+ $scope.selectLayout = function (selectedLayout) {
+ $scope.options.layout.activeLayout = listViewHelper.setLayout($routeParams.id, selectedLayout, $scope.model.config.layouts);
+ };
function showNotificationsAndReset(err, reload, successMsg) {
@@ -213,10 +221,10 @@ function listViewController($scope, $routeParams, $injector, $location, $timeout
};
}
- $timeout(function() {
- $scope.bulkStatus = "";
- $scope.actionInProgress = false;
- },
+ $timeout(function () {
+ $scope.bulkStatus = "";
+ $scope.actionInProgress = false;
+ },
500);
if (reload === true) {
@@ -225,177 +233,177 @@ function listViewController($scope, $routeParams, $injector, $location, $timeout
if (successMsg) {
localizationService.localize("bulk_done")
- .then(function(v) {
+ .then(function (v) {
notificationsService.success(v, successMsg);
});
}
}
$scope.next = function (pageNumber) {
- $scope.options.pageNumber = pageNumber;
- $scope.reloadView($scope.contentId);
- };
+ $scope.options.pageNumber = pageNumber;
+ $scope.reloadView($scope.contentId);
+ };
- $scope.goToPage = function (pageNumber) {
- $scope.options.pageNumber = pageNumber;
- $scope.reloadView($scope.contentId);
- };
+ $scope.goToPage = function (pageNumber) {
+ $scope.options.pageNumber = pageNumber;
+ $scope.reloadView($scope.contentId);
+ };
- $scope.prev = function (pageNumber) {
- $scope.options.pageNumber = pageNumber;
- $scope.reloadView($scope.contentId);
- };
+ $scope.prev = function (pageNumber) {
+ $scope.options.pageNumber = pageNumber;
+ $scope.reloadView($scope.contentId);
+ };
- /*Loads the search results, based on parameters set in prev,next,sort and so on*/
- /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state
- with simple values */
+ /*Loads the search results, based on parameters set in prev,next,sort and so on*/
+ /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state
+ with simple values */
- $scope.getContent = function() {
- $scope.reloadView($scope.contentId, true);
- }
+ $scope.getContent = function () {
+ $scope.reloadView($scope.contentId, true);
+ }
- $scope.reloadView = function (id, reloadFolders) {
+ $scope.reloadView = function (id, reloadFolders) {
- $scope.viewLoaded = false;
+ $scope.viewLoaded = false;
- listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection);
+ listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection);
- getListResultsCallback(id, $scope.options).then(function (data) {
+ getListResultsCallback(id, $scope.options).then(function (data) {
- $scope.actionInProgress = false;
- $scope.listViewResultSet = data;
+ $scope.actionInProgress = false;
+ $scope.listViewResultSet = data;
- //update all values for display
- if ($scope.listViewResultSet.items) {
- _.each($scope.listViewResultSet.items, function (e, index) {
- setPropertyValues(e);
- });
- }
+ //update all values for display
+ if ($scope.listViewResultSet.items) {
+ _.each($scope.listViewResultSet.items, function (e, index) {
+ setPropertyValues(e);
+ });
+ }
- if (reloadFolders && $scope.entityType === 'media') {
- //The folders aren't loaded - we only need to do this once since we're never changing node ids
- mediaResource.getChildFolders($scope.contentId)
+ if (reloadFolders && $scope.entityType === 'media') {
+ //The folders aren't loaded - we only need to do this once since we're never changing node ids
+ mediaResource.getChildFolders($scope.contentId)
.then(function (page) {
- $scope.folders = page.items;
- $scope.viewLoaded = true;
+ $scope.folders = page.items;
+ $scope.viewLoaded = true;
});
- } else {
- $scope.viewLoaded = true;
- }
+ } else {
+ $scope.viewLoaded = true;
+ }
- //NOTE: This might occur if we are requesting a higher page number than what is actually available, for example
- // if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last
- // available page and then re-load again
- if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) {
- $scope.options.pageNumber = $scope.listViewResultSet.totalPages;
+ //NOTE: This might occur if we are requesting a higher page number than what is actually available, for example
+ // if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last
+ // available page and then re-load again
+ if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) {
+ $scope.options.pageNumber = $scope.listViewResultSet.totalPages;
- //reload!
- $scope.reloadView(id);
- }
+ //reload!
+ $scope.reloadView(id);
+ }
- });
- };
+ });
+ };
- var searchListView = _.debounce(function () {
- $scope.$apply(function () {
- makeSearch();
- });
- }, 500);
-
- $scope.forceSearch = function (ev) {
- //13: enter
- switch (ev.keyCode) {
- case 13:
+ var searchListView = _.debounce(function () {
+ $scope.$apply(function () {
makeSearch();
- break;
- }
- };
+ });
+ }, 500);
- $scope.enterSearch = function () {
- $scope.viewLoaded = false;
- searchListView();
- };
+ $scope.forceSearch = function (ev) {
+ //13: enter
+ switch (ev.keyCode) {
+ case 13:
+ makeSearch();
+ break;
+ }
+ };
- function makeSearch() {
- if ($scope.options.filter !== null && $scope.options.filter !== undefined) {
- $scope.options.pageNumber = 1;
- $scope.reloadView($scope.contentId);
- }
- }
+ $scope.enterSearch = function () {
+ $scope.viewLoaded = false;
+ searchListView();
+ };
- $scope.isAnythingSelected = function () {
- if ($scope.selection.length === 0) {
- return false;
- } else {
- return true;
- }
- };
+ function makeSearch() {
+ if ($scope.options.filter !== null && $scope.options.filter !== undefined) {
+ $scope.options.pageNumber = 1;
+ $scope.reloadView($scope.contentId);
+ }
+ }
- $scope.selectedItemsCount = function () {
- return $scope.selection.length;
- };
+ $scope.isAnythingSelected = function () {
+ if ($scope.selection.length === 0) {
+ return false;
+ } else {
+ return true;
+ }
+ };
- $scope.clearSelection = function () {
- listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection);
- };
+ $scope.selectedItemsCount = function () {
+ return $scope.selection.length;
+ };
- $scope.getIcon = function (entry) {
- return iconHelper.convertFromLegacyIcon(entry.icon);
- };
+ $scope.clearSelection = function () {
+ listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection);
+ };
- function serial(selected, fn, getStatusMsg, index) {
- return fn(selected, index).then(function (content) {
- index++;
- $scope.bulkStatus = getStatusMsg(index, selected.length);
- return index < selected.length ? serial(selected, fn, getStatusMsg, index) : content;
- }, function (err) {
- var reload = index > 0;
- showNotificationsAndReset(err, reload);
- return err;
- });
- }
+ $scope.getIcon = function (entry) {
+ return iconHelper.convertFromLegacyIcon(entry.icon);
+ };
- function applySelected(fn, getStatusMsg, getSuccessMsg, confirmMsg) {
- var selected = $scope.selection;
- if (selected.length === 0)
- return;
- if (confirmMsg && !confirm(confirmMsg))
- return;
+ function serial(selected, fn, getStatusMsg, index) {
+ return fn(selected, index).then(function (content) {
+ index++;
+ $scope.bulkStatus = getStatusMsg(index, selected.length);
+ return index < selected.length ? serial(selected, fn, getStatusMsg, index) : content;
+ }, function (err) {
+ var reload = index > 0;
+ showNotificationsAndReset(err, reload);
+ return err;
+ });
+ }
- $scope.actionInProgress = true;
- $scope.bulkStatus = getStatusMsg(0, selected.length);
+ function applySelected(fn, getStatusMsg, getSuccessMsg, confirmMsg) {
+ var selected = $scope.selection;
+ if (selected.length === 0)
+ return;
+ if (confirmMsg && !confirm(confirmMsg))
+ return;
- return serial(selected, fn, getStatusMsg, 0).then(function (result) {
- // executes once the whole selection has been processed
- // in case of an error (caught by serial), result will be the error
- if (!(result.data && angular.isArray(result.data.notifications)))
- showNotificationsAndReset(result, true, getSuccessMsg(selected.length));
- });
- }
+ $scope.actionInProgress = true;
+ $scope.bulkStatus = getStatusMsg(0, selected.length);
- $scope.delete = function() {
+ return serial(selected, fn, getStatusMsg, 0).then(function (result) {
+ // executes once the whole selection has been processed
+ // in case of an error (caught by serial), result will be the error
+ if (!(result.data && angular.isArray(result.data.notifications)))
+ showNotificationsAndReset(result, true, getSuccessMsg(selected.length));
+ });
+ }
+
+ $scope.delete = function () {
var confirmDeleteText = "";
localizationService.localize("defaultdialogs_confirmdelete")
- .then(function(value) {
+ .then(function (value) {
confirmDeleteText = value;
var attempt =
applySelected(
- function(selected, index) { return deleteItemCallback(getIdCallback(selected[index])); },
- function(count, total) {
+ function (selected, index) { return deleteItemCallback(getIdCallback(selected[index])); },
+ function (count, total) {
var key = (total === 1 ? "bulk_deletedItemOfItem" : "bulk_deletedItemOfItems");
return localizationService.localize(key, [count, total]);
},
- function(total) {
+ function (total) {
var key = (total === 1 ? "bulk_deletedItem" : "bulk_deletedItems");
return localizationService.localize(key, [total]);
},
confirmDeleteText + "?");
if (attempt) {
- attempt.then(function() {
+ attempt.then(function () {
//executes if all is successful, let's sync the tree
var activeNode = appState.getTreeState("selectedNode");
if (activeNode) {
@@ -406,43 +414,43 @@ function listViewController($scope, $routeParams, $injector, $location, $timeout
});
};
- $scope.publish = function () {
+ $scope.publish = function () {
applySelected(
- function (selected, index) { return contentResource.publishById(getIdCallback(selected[index])); },
- function (count, total) {
- var key = (total === 1 ? "bulk_publishedItemOfItem" : "bulk_publishedItemOfItems");
- return localizationService.localize(key, [count, total]);
- },
- function (total) {
- var key = (total === 1 ? "bulk_publishedItem" : "bulk_publishedItems");
- return localizationService.localize(key, [total]);
- });
- };
+ function (selected, index) { return contentResource.publishById(getIdCallback(selected[index])); },
+ function (count, total) {
+ var key = (total === 1 ? "bulk_publishedItemOfItem" : "bulk_publishedItemOfItems");
+ return localizationService.localize(key, [count, total]);
+ },
+ function (total) {
+ var key = (total === 1 ? "bulk_publishedItem" : "bulk_publishedItems");
+ return localizationService.localize(key, [total]);
+ });
+ };
- $scope.unpublish = function() {
+ $scope.unpublish = function () {
applySelected(
- function(selected, index) { return contentResource.unPublish(getIdCallback(selected[index])); },
- function(count, total) {
+ function (selected, index) { return contentResource.unPublish(getIdCallback(selected[index])); },
+ function (count, total) {
var key = (total === 1 ? "bulk_unpublishedItemOfItem" : "bulk_unpublishedItemOfItems");
return localizationService.localize(key, [count, total]);
},
- function(total) {
+ function (total) {
var key = (total === 1 ? "bulk_unpublishedItem" : "bulk_unpublishedItems");
return localizationService.localize(key, [total]);
});
};
- $scope.move = function() {
+ $scope.move = function () {
var move = {
section: $scope.entityType,
currentNode: $scope.contentId,
- submit: function(model) {
+ submit: function (model) {
if (model.target) {
performMove(model.target);
}
editorService.close();
},
- close: function() {
+ close: function () {
editorService.close();
}
}
@@ -450,205 +458,205 @@ function listViewController($scope, $routeParams, $injector, $location, $timeout
};
- function performMove(target) {
+ function performMove(target) {
- //NOTE: With the way this applySelected/serial works, I'm not sure there's a better way currently to return
- // a specific value from one of the methods, so we'll have to try this way. Even though the first method
- // will fire once per every node moved, the destination path will be the same and we need to use that to sync.
- var newPath = null;
- applySelected(
- function(selected, index) {
- return contentResource.move({ parentId: target.id, id: getIdCallback(selected[index]) })
- .then(function(path) {
- newPath = path;
- return path;
- });
- },
- function(count, total) {
- var key = (total === 1 ? "bulk_movedItemOfItem" : "bulk_movedItemOfItems");
- return localizationService.localize(key, [count, total]);
- },
- function(total) {
- var key = (total === 1 ? "bulk_movedItem" : "bulk_movedItems");
- return localizationService.localize(key, [total]);
- })
- .then(function() {
- //executes if all is successful, let's sync the tree
- if (newPath) {
+ //NOTE: With the way this applySelected/serial works, I'm not sure there's a better way currently to return
+ // a specific value from one of the methods, so we'll have to try this way. Even though the first method
+ // will fire once per every node moved, the destination path will be the same and we need to use that to sync.
+ var newPath = null;
+ applySelected(
+ function (selected, index) {
+ return contentResource.move({ parentId: target.id, id: getIdCallback(selected[index]) })
+ .then(function (path) {
+ newPath = path;
+ return path;
+ });
+ },
+ function (count, total) {
+ var key = (total === 1 ? "bulk_movedItemOfItem" : "bulk_movedItemOfItems");
+ return localizationService.localize(key, [count, total]);
+ },
+ function (total) {
+ var key = (total === 1 ? "bulk_movedItem" : "bulk_movedItems");
+ return localizationService.localize(key, [total]);
+ })
+ .then(function () {
+ //executes if all is successful, let's sync the tree
+ if (newPath) {
- //we need to do a double sync here: first refresh the node where the content was moved,
- // then refresh the node where the content was moved from
- navigationService.syncTree({
- tree: target.nodeType ? target.nodeType : (target.metaData.treeAlias),
- path: newPath,
- forceReload: true,
- activate: false
- })
- .then(function(args) {
- //get the currently edited node (if any)
- var activeNode = appState.getTreeState("selectedNode");
- if (activeNode) {
- navigationService.reloadNode(activeNode);
- }
- });
- }
- });
- }
+ //we need to do a double sync here: first refresh the node where the content was moved,
+ // then refresh the node where the content was moved from
+ navigationService.syncTree({
+ tree: target.nodeType ? target.nodeType : (target.metaData.treeAlias),
+ path: newPath,
+ forceReload: true,
+ activate: false
+ })
+ .then(function (args) {
+ //get the currently edited node (if any)
+ var activeNode = appState.getTreeState("selectedNode");
+ if (activeNode) {
+ navigationService.reloadNode(activeNode);
+ }
+ });
+ }
+ });
+ }
$scope.copy = function () {
var copyEditor = {
section: $scope.entityType,
currentNode: $scope.contentId,
- submit: function(model) {
+ submit: function (model) {
if (model.target) {
performCopy(model.target, model.relateToOriginal);
}
editorService.close();
},
- close: function() {
+ close: function () {
editorService.close();
}
};
editorService.copy(copyEditor);
};
- function performCopy(target, relateToOriginal) {
- applySelected(
- function (selected, index) { return contentResource.copy({ parentId: target.id, id: getIdCallback(selected[index]), relateToOriginal: relateToOriginal }); },
- function (count, total) {
- var key = (total === 1 ? "bulk_copiedItemOfItem" : "bulk_copiedItemOfItems");
- return localizationService.localize(key, [count, total]);
- },
- function (total) {
- var key = (total === 1 ? "bulk_copiedItem" : "bulk_copiedItems");
- return localizationService.localize(key, [total]);
- });
- }
+ function performCopy(target, relateToOriginal) {
+ applySelected(
+ function (selected, index) { return contentResource.copy({ parentId: target.id, id: getIdCallback(selected[index]), relateToOriginal: relateToOriginal }); },
+ function (count, total) {
+ var key = (total === 1 ? "bulk_copiedItemOfItem" : "bulk_copiedItemOfItems");
+ return localizationService.localize(key, [count, total]);
+ },
+ function (total) {
+ var key = (total === 1 ? "bulk_copiedItem" : "bulk_copiedItems");
+ return localizationService.localize(key, [total]);
+ });
+ }
- function getCustomPropertyValue(alias, properties) {
- var value = '';
- var index = 0;
- var foundAlias = false;
- for (var i = 0; i < properties.length; i++) {
- if (properties[i].alias == alias) {
- foundAlias = true;
- break;
- }
- index++;
- }
+ function getCustomPropertyValue(alias, properties) {
+ var value = '';
+ var index = 0;
+ var foundAlias = false;
+ for (var i = 0; i < properties.length; i++) {
+ if (properties[i].alias == alias) {
+ foundAlias = true;
+ break;
+ }
+ index++;
+ }
- if (foundAlias) {
- value = properties[index].value;
- }
+ if (foundAlias) {
+ value = properties[index].value;
+ }
- return value;
- }
+ return value;
+ }
- /** This ensures that the correct value is set for each item in a row, we don't want to call a function during interpolation or ng-bind as performance is really bad that way */
- function setPropertyValues(result) {
+ /** This ensures that the correct value is set for each item in a row, we don't want to call a function during interpolation or ng-bind as performance is really bad that way */
+ function setPropertyValues(result) {
- //set the edit url
- result.editPath = createEditUrlCallback(result);
+ //set the edit url
+ result.editPath = createEditUrlCallback(result);
- _.each($scope.options.includeProperties, function (e, i) {
+ _.each($scope.options.includeProperties, function (e, i) {
- var alias = e.alias;
+ var alias = e.alias;
- // First try to pull the value directly from the alias (e.g. updatedBy)
- var value = result[alias];
+ // First try to pull the value directly from the alias (e.g. updatedBy)
+ var value = result[alias];
- // If this returns an object, look for the name property of that (e.g. owner.name)
- if (value === Object(value)) {
- value = value['name'];
- }
+ // If this returns an object, look for the name property of that (e.g. owner.name)
+ if (value === Object(value)) {
+ value = value['name'];
+ }
- // If we've got nothing yet, look at a user defined property
- if (typeof value === 'undefined') {
- value = getCustomPropertyValue(alias, result.properties);
- }
+ // If we've got nothing yet, look at a user defined property
+ if (typeof value === 'undefined') {
+ value = getCustomPropertyValue(alias, result.properties);
+ }
- // If we have a date, format it
- if (isDate(value)) {
- value = value.substring(0, value.length - 3);
- }
+ // If we have a date, format it
+ if (isDate(value)) {
+ value = value.substring(0, value.length - 3);
+ }
- // set what we've got on the result
- result[alias] = value;
- });
+ // set what we've got on the result
+ result[alias] = value;
+ });
- }
+ }
- function isDate(val) {
- if (angular.isString(val)) {
- return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/);
- }
- return false;
- }
+ function isDate(val) {
+ if (angular.isString(val)) {
+ return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/);
+ }
+ return false;
+ }
- function initView() {
- //default to root id if the id is undefined
- var id = $routeParams.id;
- if (id === undefined) {
- id = -1;
- }
+ function initView() {
+ //default to root id if the id is undefined
+ var id = $routeParams.id;
+ if (id === undefined) {
+ id = -1;
+ }
- getContentTypesCallback(id).then(function (items) {
- $scope.listViewAllowedTypes = items;
- });
+ getContentTypesCallback(id).then(function (items) {
+ $scope.listViewAllowedTypes = items;
+ });
- $scope.contentId = id;
- $scope.isTrashed = id === "-20" || id === "-21";
+ $scope.contentId = id;
+ $scope.isTrashed = id === "-20" || id === "-21";
- $scope.options.allowBulkPublish = $scope.options.allowBulkPublish && !$scope.isTrashed;
- $scope.options.allowBulkUnpublish = $scope.options.allowBulkUnpublish && !$scope.isTrashed;
+ $scope.options.allowBulkPublish = $scope.options.allowBulkPublish && !$scope.isTrashed;
+ $scope.options.allowBulkUnpublish = $scope.options.allowBulkUnpublish && !$scope.isTrashed;
- $scope.options.bulkActionsAllowed = $scope.options.allowBulkPublish ||
- $scope.options.allowBulkUnpublish ||
- $scope.options.allowBulkCopy ||
- $scope.options.allowBulkMove ||
- $scope.options.allowBulkDelete;
+ $scope.options.bulkActionsAllowed = $scope.options.allowBulkPublish ||
+ $scope.options.allowBulkUnpublish ||
+ $scope.options.allowBulkCopy ||
+ $scope.options.allowBulkMove ||
+ $scope.options.allowBulkDelete;
- $scope.reloadView($scope.contentId, true);
- }
+ $scope.reloadView($scope.contentId, true);
+ }
- function getLocalizedKey(alias) {
+ function getLocalizedKey(alias) {
- switch (alias) {
- case "sortOrder":
- return "general_sort";
- case "updateDate":
- return "content_updateDate";
- case "updater":
- return "content_updatedBy";
- case "createDate":
- return "content_createDate";
- case "owner":
- return "content_createBy";
- case "published":
- return "content_isPublished";
- case "contentTypeAlias":
- //TODO: Check for members
- return $scope.entityType === "content" ? "content_documentType" : "content_mediatype";
- case "email":
- return "general_email";
- case "username":
- return "general_username";
- }
- return alias;
- }
+ switch (alias) {
+ case "sortOrder":
+ return "general_sort";
+ case "updateDate":
+ return "content_updateDate";
+ case "updater":
+ return "content_updatedBy";
+ case "createDate":
+ return "content_createDate";
+ case "owner":
+ return "content_createBy";
+ case "published":
+ return "content_isPublished";
+ case "contentTypeAlias":
+ //TODO: Check for members
+ return $scope.entityType === "content" ? "content_documentType" : "content_mediatype";
+ case "email":
+ return "general_email";
+ case "username":
+ return "general_username";
+ }
+ return alias;
+ }
- function getItemKey(itemId) {
- for (var i = 0; i < $scope.listViewResultSet.items.length; i++) {
- var item = $scope.listViewResultSet.items[i];
- if (item.id === itemId) {
- return item.key;
- }
- }
- }
+ function getItemKey(itemId) {
+ for (var i = 0; i < $scope.listViewResultSet.items.length; i++) {
+ var item = $scope.listViewResultSet.items[i];
+ if (item.id === itemId) {
+ return item.key;
+ }
+ }
+ }
- //GO!
- initView();
+ //GO!
+ initView();
}
diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs
index 427dadb2c9..16eb3b9e87 100644
--- a/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs
@@ -4,9 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using Newtonsoft.Json;
-using Umbraco.Core.Models;
-using Umbraco.Core.Models.Validation;
-using Umbraco.Web.WebApi;
+using Newtonsoft.Json.Converters;
namespace Umbraco.Web.Models.ContentEditing
{
@@ -22,8 +20,11 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "createDate")]
public DateTime CreateDate { get; set; }
+ ///
+ /// Boolean indicating if this item is published or not based on it's
+ ///
[DataMember(Name = "published")]
- public bool Published { get; set; }
+ public bool Published => State == ContentSavedState.Published || State == ContentSavedState.PublishedPendingChanges;
///
/// Determines if the content item is a draft
@@ -44,6 +45,16 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "sortOrder")]
public int SortOrder { get; set; }
+ ///
+ /// The saved/published state of an item
+ ///
+ ///
+ /// This is nullable since it's only relevant for content (non-content like media + members will be null)
+ ///
+ [DataMember(Name = "state")]
+ [JsonConverter(typeof(StringEnumConverter))]
+ public ContentSavedState? State { get; set; }
+
protected bool Equals(ContentItemBasic other)
{
return Id == other.Id;
diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentSavedState.cs b/src/Umbraco.Web/Models/ContentEditing/ContentSavedState.cs
index f433af58d6..2ceb682a13 100644
--- a/src/Umbraco.Web/Models/ContentEditing/ContentSavedState.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/ContentSavedState.cs
@@ -8,21 +8,21 @@
///
/// The item isn't created yet
///
- NotCreated,
+ NotCreated = 1,
///
/// The item is saved but isn't published
///
- Draft,
+ Draft = 2,
///
/// The item is published and there are no pending changes
///
- Published,
+ Published = 3,
///
/// The item is published and there are pending changes
///
- PublishedPendingChanges
+ PublishedPendingChanges = 4
}
}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
index 1334cb1572..1da5bbbb44 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentMapperProfile.cs
@@ -32,7 +32,6 @@ namespace Umbraco.Web.Models.Mapping
var contentTypeBasicResolver = new ContentTypeBasicResolver();
var defaultTemplateResolver = new DefaultTemplateResolver();
var variantResolver = new ContentVariantResolver(localizationService);
- var contentSavedStateResolver = new ContentSavedStateResolver();
//FROM IContent TO ContentItemDisplay
CreateMap()
@@ -67,7 +66,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.Segment, opt => opt.Ignore())
.ForMember(dest => dest.Language, opt => opt.Ignore())
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
- .ForMember(dest => dest.State, opt => opt.ResolveUsing(contentSavedStateResolver))
+ .ForMember(dest => dest.State, opt => opt.ResolveUsing>())
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver));
//FROM IContent TO ContentItemBasic
@@ -81,63 +80,76 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
.ForMember(dest => dest.Alias, opt => opt.Ignore())
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
- .ForMember(dest => dest.UpdateDate, opt => opt.ResolveUsing())
- .ForMember(dest => dest.Published, opt => opt.ResolveUsing())
- .ForMember(dest => dest.Name, opt => opt.ResolveUsing());
+ .ForMember(dest => dest.UpdateDate, opt => opt.ResolveUsing())
+ .ForMember(dest => dest.Name, opt => opt.ResolveUsing())
+ .ForMember(dest => dest.State, opt => opt.ResolveUsing>());
//FROM IContent TO ContentPropertyCollectionDto
//NOTE: the property mapping for cultures relies on a culture being set in the mapping context
CreateMap();
}
- }
- internal class CultureUpdateDateResolver : IValueResolver, DateTime>
- {
- public DateTime Resolve(IContent source, ContentItemBasic destination, DateTime destMember, ResolutionContext context)
+ ///
+ /// Resolves the update date for a content item/content variant
+ ///
+ private class UpdateDateResolver : IValueResolver, DateTime>
{
- var culture = context.GetCulture();
-
- //a culture needs to be in the context for a variant content item
- if (culture == null || source.ContentType.VariesByCulture() == false)
- return source.UpdateDate;
-
- var pubDate = source.GetPublishDate(culture);
- return pubDate.HasValue ? pubDate.Value : source.UpdateDate;
- }
- }
-
- internal class CulturePublishedResolver : IValueResolver, bool>
- {
- public bool Resolve(IContent source, ContentItemBasic destination, bool destMember, ResolutionContext context)
- {
- var culture = context.GetCulture();
-
- //a culture needs to be in the context for a variant content item
- if (culture == null || source.ContentType.VariesByCulture() == false)
- return source.Published;
-
- return source.IsCulturePublished(culture);
- }
- }
-
- internal class CultureNameResolver : IValueResolver, string>
- {
- public string Resolve(IContent source, ContentItemBasic destination, string destMember, ResolutionContext context)
- {
- var culture = context.GetCulture();
-
- //a culture needs to be in the context for a variant content item
- if (culture == null || source.ContentType.VariesByCulture() == false)
- return source.Name;
-
- if (source.CultureNames.TryGetValue(culture, out var name) && !string.IsNullOrWhiteSpace(name))
+ public DateTime Resolve(IContent source, ContentItemBasic destination, DateTime destMember, ResolutionContext context)
{
- return name;
- }
- else
- {
- return $"({ source.Name })";
+ var culture = context.GetCulture();
+
+ //a culture needs to be in the context for a variant content item
+ if (culture == null || source.ContentType.VariesByCulture() == false)
+ return source.UpdateDate;
+
+ var pubDate = source.GetPublishDate(culture);
+ return pubDate.HasValue ? pubDate.Value : source.UpdateDate;
}
}
+
+ ///
+ /// Resolves the published flag for a content item/content variant
+ ///
+ private class PublishedResolver : IValueResolver, bool>
+ {
+ public bool Resolve(IContent source, ContentItemBasic destination, bool destMember, ResolutionContext context)
+ {
+ var culture = context.GetCulture();
+
+ //a culture needs to be in the context for a variant content item
+ if (culture == null || source.ContentType.VariesByCulture() == false)
+ return source.Published;
+
+ return source.IsCulturePublished(culture);
+ }
+ }
+
+ ///
+ /// Resolves the name for a content item/content variant
+ ///
+ private class NameResolver : IValueResolver, string>
+ {
+ public string Resolve(IContent source, ContentItemBasic destination, string destMember, ResolutionContext context)
+ {
+ var culture = context.GetCulture();
+
+ //a culture needs to be in the context for a variant content item
+ if (culture == null || source.ContentType.VariesByCulture() == false)
+ return source.Name;
+
+ if (source.CultureNames.TryGetValue(culture, out var name) && !string.IsNullOrWhiteSpace(name))
+ {
+ return name;
+ }
+ else
+ {
+ return $"({ source.Name })";
+ }
+ }
+ }
+
}
+
+
+
}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentSavedStateResolver.cs b/src/Umbraco.Web/Models/Mapping/ContentSavedStateResolver.cs
index 4fb4d3370a..b2b4408110 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentSavedStateResolver.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentSavedStateResolver.cs
@@ -6,9 +6,30 @@ using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Models.Mapping
{
- internal class ContentSavedStateResolver : IValueResolver
+
+ ///
+ /// Returns the for an item
+ ///
+ ///
+ internal class ContentBasicSavedStateResolver : IValueResolver, ContentSavedState?>
+ where T : ContentPropertyBasic
{
- public ContentSavedState Resolve(IContent source, ContentVariantDisplay destination, ContentSavedState destMember, ResolutionContext context)
+ private readonly ContentSavedStateResolver _inner = new ContentSavedStateResolver();
+
+ public ContentSavedState? Resolve(IContent source, IContentProperties destination, ContentSavedState? destMember, ResolutionContext context)
+ {
+ return _inner.Resolve(source, destination, default, context);
+ }
+ }
+
+ ///
+ /// Returns the for an item
+ ///
+ ///
+ internal class ContentSavedStateResolver : IValueResolver, ContentSavedState>
+ where T : ContentPropertyBasic
+ {
+ public ContentSavedState Resolve(IContent source, IContentProperties destination, ContentSavedState destMember, ResolutionContext context)
{
PublishedState publishedState;
bool isEdited;
diff --git a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs
index caa9f29e70..c07d66b6e2 100644
--- a/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/MediaMapperProfile.cs
@@ -44,7 +44,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(contentTreeNodeUrlResolver))
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
.ForMember(dest => dest.Errors, opt => opt.Ignore())
- .ForMember(dest => dest.Published, opt => opt.Ignore())
+ .ForMember(dest => dest.State, opt => opt.UseValue(null))
.ForMember(dest => dest.Edited, opt => opt.Ignore())
.ForMember(dest => dest.Updater, opt => opt.Ignore())
.ForMember(dest => dest.Alias, opt => opt.Ignore())
@@ -62,7 +62,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed))
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
- .ForMember(dest => dest.Published, opt => opt.Ignore())
+ .ForMember(dest => dest.State, opt => opt.UseValue(null))
.ForMember(dest => dest.Edited, opt => opt.Ignore())
.ForMember(dest => dest.Updater, opt => opt.Ignore())
.ForMember(dest => dest.Alias, opt => opt.Ignore())
diff --git a/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs
index 22d499f3d6..f64d8dc529 100644
--- a/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/MemberMapperProfile.cs
@@ -73,7 +73,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.MembershipScenario, opt => opt.ResolveUsing(src => membershipScenarioMappingResolver.Resolve(src)))
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
.ForMember(dest => dest.Errors, opt => opt.Ignore())
- .ForMember(dest => dest.Published, opt => opt.Ignore())
+ .ForMember(dest => dest.State, opt => opt.UseValue(null))
.ForMember(dest => dest.Edited, opt => opt.Ignore())
.ForMember(dest => dest.Updater, opt => opt.Ignore())
.ForMember(dest => dest.Alias, opt => opt.Ignore())
@@ -91,7 +91,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
.ForMember(dest => dest.Username, opt => opt.MapFrom(src => src.Username))
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
- .ForMember(dest => dest.Published, opt => opt.Ignore())
+ .ForMember(dest => dest.State, opt => opt.UseValue(null))
.ForMember(dest => dest.Edited, opt => opt.Ignore())
.ForMember(dest => dest.Updater, opt => opt.Ignore())
.ForMember(dest => dest.Alias, opt => opt.Ignore())
@@ -115,7 +115,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.Path, opt => opt.Ignore())
.ForMember(dest => dest.SortOrder, opt => opt.Ignore())
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
- .ForMember(dest => dest.Published, opt => opt.Ignore())
+ .ForMember(dest => dest.State, opt => opt.UseValue(ContentSavedState.Draft))
.ForMember(dest => dest.Edited, opt => opt.Ignore())
.ForMember(dest => dest.Updater, opt => opt.Ignore())
.ForMember(dest => dest.Trashed, opt => opt.Ignore())