From afbeb50d552aa5b77dcba4f1a55e58746a845f1b Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 12 Sep 2014 14:07:42 +1000 Subject: [PATCH] List view pre-values working with fields and headers, list view now rendering data again, removed the config ui bits from the content type editor --- .../includeproperties.prevalues.controller.js | 117 +++++++ .../listview/includeproperties.prevalues.html | 51 +++ .../listview/listview.controller.js | 324 ++++++++++-------- .../propertyeditors/listview/listview.html | 28 +- .../controls/ContentTypeControlNew.ascx | 216 +----------- .../Editors/ContentTypeControllerBase.cs | 132 +++---- .../PropertyEditors/ListViewPropertyEditor.cs | 6 +- 7 files changed, 428 insertions(+), 446 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.html diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js new file mode 100644 index 0000000000..8b5ad33082 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.controller.js @@ -0,0 +1,117 @@ +function includePropsPreValsController($rootScope, $scope, localizationService, contentTypeResource) { + + if (!$scope.model.value) { + $scope.model.value = []; + } + + $scope.propertyAliases = []; + $scope.selectedField = null; + $scope.systemFields = [ + { value: "updateDate", name: "Last edited" }, + { value: "updater", name: "Updated by" }, + { value: "createDate", name: "Created" }, + { value: "creator", name: "Created by" } + ]; + + $scope.getLocalizedKey = function(alias) { + switch (alias) { + case "updateDate": + return "content_updateDate"; + case "updater": + return "content_updatedBy"; + case "createDate": + return "content_createDate"; + case "creator": + return "content_createBy"; + } + return alias; + } + + $scope.removeField = function(e) { + $scope.model.value = _.reject($scope.model.value, function (x) { + return x.alias === e.alias; + }); + } + + //now we'll localize these strings, for some reason the directive doesn't work inside of the select group with an ng-model declared + _.each($scope.systemFields, function (e, i) { + var key = $scope.getLocalizedKey(e.value); + localizationService.localize(key).then(function (v) { + e.name = v; + }); + }); + + // Return a helper with preserved width of cells + var fixHelper = function (e, ui) { + var h = ui.clone(); + + h.children().each(function () { + $(this).width($(this).width()); + }); + h.css("background-color", "lightgray"); + + return h; + }; + + $scope.sortableOptions = { + helper: fixHelper, + handle: ".handle", + opacity: 0.5, + axis: 'y', + containment: 'parent', + cursor: 'move', + items: '> tr', + tolerance: 'pointer', + update: function (e, ui) { + + // Get the new and old index for the moved element (using the text as the identifier) + var newIndex = ui.item.index(); + var movedAlias = $('.alias-value', ui.item).text(); + var originalIndex = getAliasIndexByText(movedAlias); + + // Move the element in the model + if (originalIndex > -1) { + var movedElement = $scope.model.value[originalIndex]; + $scope.model.value.splice(originalIndex, 1); + $scope.model.value.splice(newIndex, 0, movedElement); + } + } + }; + + contentTypeResource.getAllPropertyTypeAliases().then(function(data) { + $scope.propertyAliases = data; + }); + + $scope.addField = function () { + + var val = $scope.selectedField; + var isSystem = val.startsWith("_system_"); + if (isSystem) { + val = val.trimStart("_system_"); + } + + var exists = _.find($scope.model.value, function (i) { + return i.alias === val; + }); + if (!exists) { + $scope.model.value.push({ + alias: val, + isSystem: isSystem ? 1 : 0 + }); + } + } + + function getAliasIndexByText(value) { + for (var i = 0; i < $scope.model.value.length; i++) { + if ($scope.model.value[i].alias === value) { + return i; + } + } + + return -1; + } + +} + + +angular.module("umbraco").controller("Umbraco.PrevalueEditors.ListViewController", includePropsPreValsController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.html new file mode 100644 index 0000000000..27459ed055 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/includeproperties.prevalues.html @@ -0,0 +1,51 @@ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + +
AliasHeader
+ + + {{val.alias}} + + {{val.alias}} + + (system field) + + + + {{val.alias}} + + + +
+
+ + +
\ No newline at end of file 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 87c23cadb9..84117c5b23 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,4 +1,4 @@ -function listViewController($rootScope, $scope, $routeParams, $injector, notificationsService, iconHelper, dialogService, editorState) { +function listViewController($rootScope, $scope, $routeParams, $injector, notificationsService, iconHelper, dialogService, editorState, localizationService) { //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 @@ -28,76 +28,86 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific totalPages: 0, items: [] }; - - // Set "default default" options (i.e. those if no container configuration has been saved) + $scope.options = { pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10, pageNumber: 1, filter: '', - orderBy: $scope.model.config.orderBy ? $scope.model.config.orderBy : 'UpdateDate', - orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection : "desc" - //orderBy: 'updateDate', - //orderDirection: "desc", + orderBy: $scope.model.config.orderBy ? $scope.model.config.orderBy : 'updateDate', + orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection : "desc", + includeProperties: $scope.model.config.includeProperties ? $scope.model.config.includeProperties : [ + { alias: 'updateDate', header: 'Last edited', isSystem : 1 }, + { alias: 'updater', header: 'Last edited by', isSystem: 1 } + ], allowBulkPublish: true, allowBulkUnpublish: true, - allowBulkDelete: true, - additionalColumns: [ - { alias: 'UpdateDate', header: 'Last edited', localizationKey: 'defaultdialogs_lastEdited' }, - { alias: 'Updator', header: 'Last edited', localizationKey: 'content_updatedBy' } - ] + allowBulkDelete: true, }; - // Retrieve the container configuration for the content type and set options before presenting initial view - contentTypeResource.getContainerConfig($routeParams.id) - .then(function (config) { - if (typeof config.pageSize !== 'undefined') { - $scope.options.pageSize = config.pageSize; - } - if (typeof config.additionalColumns !== 'undefined') { - $scope.options.additionalColumns = config.additionalColumns; - } - if (typeof config.orderBy !== 'undefined') { - $scope.options.orderBy = config.orderBy; - } - if (typeof config.orderDirection !== 'undefined') { - $scope.options.orderDirection = config.orderDirection; - } - if (typeof config.allowBulkPublish !== 'undefined') { - $scope.options.allowBulkPublish = config.allowBulkPublish; - } - if (typeof config.allowBulkUnpublish !== 'undefined') { - $scope.options.allowBulkUnpublish = config.allowBulkUnpublish; - } - if (typeof config.allowBulkDelete !== 'undefined') { - $scope.options.allowBulkDelete = config.allowBulkDelete; - } + //update all of the system includeProperties to enable sorting + _.each($scope.options.includeProperties, function(e, i) { + if (e.isSystem) { + e.allowSorting = true; + //localize the header + var key = getLocalizedKey(e.alias); + localizationService.localize(key).then(function (v) { + e.header = v; + }); + } + }); - $scope.initView(); - }); + //// Retrieve the container configuration for the content type and set options before presenting initial view + //contentTypeResource.getContainerConfig($routeParams.id) + // .then(function(config) { + // if (typeof config.pageSize !== 'undefined') { + // $scope.options.pageSize = config.pageSize; + // } + // if (typeof config.additionalColumns !== 'undefined') { + // $scope.options.additionalColumns = config.additionalColumns; + // } + // if (typeof config.orderBy !== 'undefined') { + // $scope.options.orderBy = config.orderBy; + // } + // if (typeof config.orderDirection !== 'undefined') { + // $scope.options.orderDirection = config.orderDirection; + // } + // if (typeof config.allowBulkPublish !== 'undefined') { + // $scope.options.allowBulkPublish = config.allowBulkPublish; + // } + // if (typeof config.allowBulkUnpublish !== 'undefined') { + // $scope.options.allowBulkUnpublish = config.allowBulkUnpublish; + // } + // if (typeof config.allowBulkDelete !== 'undefined') { + // $scope.options.allowBulkDelete = config.allowBulkDelete; + // } - $scope.next = function () { + // $scope.initView(); + // }); + + $scope.next = function() { if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) { $scope.options.pageNumber++; $scope.reloadView($scope.contentId); - saveLastPageNumber(); + //saveLastPageNumber(); } }; - $scope.goToPage = function (pageNumber) { + $scope.goToPage = function(pageNumber) { $scope.options.pageNumber = pageNumber + 1; $scope.reloadView($scope.contentId); - saveLastPageNumber(); + //saveLastPageNumber(); }; - $scope.sort = function (field, allow) { + $scope.sort = function(field, allow) { if (allow) { $scope.options.orderBy = field; if ($scope.options.orderDirection === "desc") { $scope.options.orderDirection = "asc"; - } else { + } + else { $scope.options.orderDirection = "desc"; } @@ -105,48 +115,29 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; - $scope.prev = function () { + $scope.prev = function() { if ($scope.options.pageNumber > 1) { $scope.options.pageNumber--; $scope.reloadView($scope.contentId); - saveLastPageNumber(); - } - }; - - saveLastPageNumber = function () { - // Saves the last page number into rootScope, so we can retrieve it when returning to the list and - // re-present the correct page - $rootScope.lastListViewPageViewed = { - contentId: $scope.contentId, - pageNumber: $scope.options.pageNumber - }; - }; - - $scope.initView = function () { - if ($routeParams.id) { - $scope.pagination = new Array(10); - $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); - - $scope.contentId = $routeParams.id; - $scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21"; - - // If we have a last page number saved, go straight to that one - if ($rootScope.lastListViewPageViewed && $rootScope.lastListViewPageViewed.contentId == $scope.contentId) { - $scope.goToPage($rootScope.lastListViewPageViewed.pageNumber - 1); - } else { - $scope.reloadView($scope.contentId); - } + //saveLastPageNumber(); } }; + /*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.reloadView = function (id) { - contentResource.getChildren(id, $scope.options).then(function (data) { + $scope.reloadView = function(id) { + contentResource.getChildren(id, $scope.options).then(function(data) { $scope.listViewResultSet = data; + + //update all values for display + _.each($scope.listViewResultSet.items, function(e, index) { + setPropertyValues(e); + }); + $scope.pagination = []; for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) { @@ -160,51 +151,11 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }); }; - $scope.getColumnName = function (index) { - return $scope.options.additionalColumns[index].header; - }; - - $scope.getColumnLocalizationKey = function (index) { - return $scope.options.additionalColumns[index].localizationKey; - }; - - $scope.getPropertyValue = function (alias, result) { - - // Camel-case the alias - alias = alias.charAt(0).toLowerCase() + alias.slice(1); - - // 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 we've got nothing yet, look at a user defined property - if (typeof value === 'undefined') { - value = $scope.getCustomPropertyValue(alias, result.properties); - } - - // If we have a date, format it - if (isDate(value)) { - value = value.substring(0, value.length - 3); - } - - // Return what we've got - return value; - - }; - - isDate = function (val) { - return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); - }; - - $scope.getCustomPropertyValue = function (alias, properties) { + function getCustomPropertyValue(alias, properties) { var value = ''; var index = 0; var foundAlias = false; - for (var i = 0; i < properties.length; i++) { + for (var i = 0; i < properties.length; i++) { if (properties[i].alias == alias) { foundAlias = true; break; @@ -220,12 +171,12 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }; //assign debounce method to the search to limit the queries - $scope.search = _.debounce(function () { + $scope.search = _.debounce(function() { $scope.options.pageNumber = 1; $scope.reloadView($scope.contentId); }, 100); - $scope.selectAll = function ($event) { + $scope.selectAll = function($event) { var checkbox = $event.target; if (!angular.isArray($scope.listViewResultSet.items)) { return; @@ -236,30 +187,30 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; - $scope.isSelectedAll = function () { + $scope.isSelectedAll = function() { if (!angular.isArray($scope.listViewResultSet.items)) { return false; } - return _.every($scope.listViewResultSet.items, function (item) { + return _.every($scope.listViewResultSet.items, function(item) { return item.selected; }); }; - $scope.isAnythingSelected = function () { + $scope.isAnythingSelected = function() { if (!angular.isArray($scope.listViewResultSet.items)) { return false; } - return _.some($scope.listViewResultSet.items, function (item) { + return _.some($scope.listViewResultSet.items, function(item) { return item.selected; }); }; - $scope.getIcon = function (entry) { + $scope.getIcon = function(entry) { return iconHelper.convertFromLegacyIcon(entry.icon); }; - $scope.delete = function () { - var selected = _.filter($scope.listViewResultSet.items, function (item) { + $scope.delete = function() { + var selected = _.filter($scope.listViewResultSet.items, function(item) { return item.selected; }); var total = selected.length; @@ -274,7 +225,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific for (var i = 0; i < selected.length; i++) { $scope.bulkStatus = "Deleted doc " + current + " out of " + total + " documents"; - contentResource.deleteById(selected[i].id).then(function (data) { + contentResource.deleteById(selected[i].id).then(function(data) { if (current === total) { notificationsService.success("Bulk action", "Deleted " + total + "documents"); $scope.bulkStatus = ""; @@ -288,8 +239,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }; - $scope.publish = function () { - var selected = _.filter($scope.listViewResultSet.items, function (item) { + $scope.publish = function() { + var selected = _.filter($scope.listViewResultSet.items, function(item) { return item.selected; }); var total = selected.length; @@ -305,7 +256,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.bulkStatus = "Publishing " + current + " out of " + total + " documents"; contentResource.publishById(selected[i].id) - .then(function (content) { + .then(function(content) { if (current == total) { notificationsService.success("Bulk action", "Published " + total + "documents"); $scope.bulkStatus = ""; @@ -313,7 +264,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.actionInProgress = false; } current++; - }, function (err) { + }, function(err) { $scope.bulkStatus = ""; $scope.reloadView($scope.contentId); @@ -331,8 +282,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; - $scope.unpublish = function () { - var selected = _.filter($scope.listViewResultSet.items, function (item) { + $scope.unpublish = function() { + var selected = _.filter($scope.listViewResultSet.items, function(item) { return item.selected; }); var total = selected.length; @@ -348,7 +299,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific $scope.bulkStatus = "Unpublishing " + current + " out of " + total + " documents"; contentResource.unPublish(selected[i].id) - .then(function (content) { + .then(function(content) { if (current == total) { notificationsService.success("Bulk action", "Published " + total + "documents"); @@ -362,18 +313,101 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; - $scope.includeProperties = $scope.model.config.includeProperties ? _.map($scope.model.config.includeProperties, function (i) { - if (!i.label) - i.label = i.value.replace(/([A-Z]?[a-z]+)/g, '$1 ').trim(' '); - if (typeof (i.isProperty) == "undefined") - i.isProperty = !i.value.match("contentTypeAlias|createDate|icon|owner|published|sortOrder|updateDat|updator"); - if (!i.isProperty && !i.sortBy) - i.sortBy = i.value.substring(0, 1).toUpperCase() + i.value.slice(1); - // TODO: Add sort logic for custom properties. - //else if (!i.sortBy) - // ; - return i; - }) : {}; + $scope.includeProperties = $scope.model.config.includeProperties ? _.map($scope.model.config.includeProperties, function(i) { + if (!i.label) + i.label = i.value.replace(/([A-Z]?[a-z]+)/g, '$1 ').trim(' '); + if (typeof (i.isProperty) == "undefined") + i.isProperty = !i.value.match("contentTypeAlias|createDate|icon|owner|published|sortOrder|updateDate|updater"); + if (!i.isProperty && !i.sortBy) + i.sortBy = i.value.substring(0, 1).toUpperCase() + i.value.slice(1); + // TODO: Add sort logic for custom properties. + //else if (!i.sortBy) + // ; + return i; + }) : {}; + + /** 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) { + + _.each($scope.options.includeProperties, function (e, i) { + + var alias = e.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 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); + } + + // set what we've got on the result + result[alias] = value; + }); + + + }; + + function isDate(val) { + return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); + }; + + //function saveLastPageNumber() { + // //TODO: Fix this up, we don't want to use $rootScope + + // // Saves the last page number into rootScope, so we can retrieve it when returning to the list and + // // re-present the correct page + // $rootScope.lastListViewPageViewed = { + // contentId: $scope.contentId, + // pageNumber: $scope.options.pageNumber + // }; + //}; + + function initView() { + if ($routeParams.id) { + $scope.pagination = new Array(10); + $scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id); + + $scope.contentId = $routeParams.id; + $scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21"; + + //// If we have a last page number saved, go straight to that one + //if ($rootScope.lastListViewPageViewed && $rootScope.lastListViewPageViewed.contentId == $scope.contentId) { + // $scope.goToPage($rootScope.lastListViewPageViewed.pageNumber - 1); + //} + //else { + $scope.reloadView($scope.contentId); + //} + } + }; + + function getLocalizedKey(alias) { + + switch (alias) { + case "updateDate": + return "content_updateDate"; + case "updater": + return "content_updatedBy"; + case "createDate": + return "content_createDate"; + case "creator": + return "content_createBy"; + } + return alias; + } + + //GO! + initView(); } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 63617ec8d7..d80a587aca 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -54,10 +54,9 @@ - - - {{getColumnName($index)}} - {{getColumnName($index)}} + + + @@ -95,27 +94,22 @@ - {{result.name}} + - - {{getPropertyValue(column.alias, result)}} + + {{result[column.alias]}} - - - - {{result[property.value]}} - -
- {{props.value}} -
+ - +