diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index e3f6a2a7e5..da0420dbbd 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -680,43 +680,7 @@ namespace Umbraco.Core.Persistence.Repositories return result; } - - private string GetDatabaseFieldNameForOrderBy(string orderBy) - { - // Translate the passed order by field (which were originally defined for in-memory object sorting - // of ContentItemBasic instances) to the database field names. - switch (orderBy.ToUpperInvariant()) - { - case "NAME": - return "cmsDocument.text"; - case "OWNER": - //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter - return "umbracoNode.nodeUser"; - case "UPDATER": - //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter - return "cmsDocument.documentUser"; - default: - return orderBy; - } - } - - private string GetEntityPropertyNameForOrderBy(string orderBy) - { - // Translate the passed order by field (which were originally defined for in-memory object sorting - // of ContentItemBasic instances) to the IContent property names. - switch (orderBy.ToUpperInvariant()) - { - case "OWNER": - //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter - return "CreatorId"; - case "UPDATER": - //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter - return "WriterId"; - default: - return orderBy; - } - } - + #endregion #region IRecycleBinRepository members @@ -728,6 +692,21 @@ namespace Umbraco.Core.Persistence.Repositories #endregion + protected override string GetDatabaseFieldNameForOrderBy(string orderBy) + { + var result = base.GetDatabaseFieldNameForOrderBy(orderBy); + if (result == orderBy) + { + switch (orderBy.ToUpperInvariant()) + { + case "UPDATER": + //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter + return "cmsDocument.documentUser"; + } + } + return result; + } + private IEnumerable ProcessQuery(Sql sql) { //NOTE: This doesn't allow properties to be part of the query diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index a8bfad0fbd..f583bc5c84 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -420,7 +420,7 @@ namespace Umbraco.Core.Persistence.Repositories .AsQueryable(); // Now we need to ensure this result is also ordered by the same order by clause - var orderByProperty = GetIMediaPropertyNameForOrderBy(orderBy); + var orderByProperty = GetEntityPropertyNameForOrderBy(orderBy); if (orderDirection == Direction.Ascending) { result = media.OrderBy(orderByProperty); @@ -462,32 +462,6 @@ namespace Umbraco.Core.Persistence.Repositories dto, contentTypes.First(ct => ct.Id == dto.ContentDto.ContentTypeId), propertyData[dto.NodeId])); - } - - private string GetDatabaseFieldNameForOrderBy(string orderBy) - { - // Translate the passed order by field (which were originally defined for in-memory object sorting - // of ContentItemBasic instances) to the database field names. - switch (orderBy) - { - case "Name": - return "umbracoNode.text"; - default: - return "umbracoNode.sortOrder"; - } - } - - private string GetIMediaPropertyNameForOrderBy(string orderBy) - { - // Translate the passed order by field (which were originally defined for in-memory object sorting - // of ContentItemBasic instances) to the IMedia property names. - switch (orderBy) - { - case "Name": - return "Name"; - default: - return "SortOrder"; - } } /// diff --git a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs index 77b94e3553..4aaa4b1f0e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs @@ -332,6 +332,38 @@ ON cmsPropertyType.contentTypeId = docData.contentType", docSql.Arguments); public DateTime CreateDate { get; set; } public IContentTypeComposition Composition { get; set; } } - + + protected virtual string GetDatabaseFieldNameForOrderBy(string orderBy) + { + // Translate the passed order by field (which were originally defined for in-memory object sorting + // of ContentItemBasic instances) to the database field names. + switch (orderBy.ToUpperInvariant()) + { + case "NAME": + return "cmsDocument.text"; + case "OWNER": + //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter + return "umbracoNode.nodeUser"; + default: + return orderBy; + } + } + + protected virtual string GetEntityPropertyNameForOrderBy(string orderBy) + { + // Translate the passed order by field (which were originally defined for in-memory object sorting + // of ContentItemBasic instances) to the IMedia property names. + switch (orderBy.ToUpperInvariant()) + { + case "OWNER": + //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter + return "CreatorId"; + case "UPDATER": + //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter + return "WriterId"; + default: + return orderBy; + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/listview.less b/src/Umbraco.Web.UI.Client/src/less/listview.less index 0e37893226..25155a6828 100644 --- a/src/Umbraco.Web.UI.Client/src/less/listview.less +++ b/src/Umbraco.Web.UI.Client/src/less/listview.less @@ -44,7 +44,8 @@ position: absolute; top: 8px; left:5px; - color: @gray + color: @gray; + cursor:pointer; } .umb-listview table input[type="text"] { @@ -82,18 +83,25 @@ color: @black } -.umb-listview table a.no-sort { +.umb-listview table thead a { cursor: default; } -.umb-listview table a.no-sort:hover { +.umb-listview table thead a:hover { text-decoration: none; } +.umb-listview table thead a.sortable { + cursor: pointer; +} +.umb-listview table thead a.sortable span:hover { + text-decoration: underline; +} + .umb-listview .icon-star { color: @grayLight } -.umb-listview .selected i.icon, .umb-listview tr:hover i.icon{display: none} +.umb-listview .selected i.icon, .umb-listview tbody tr:hover i.icon{display: none} .umb-listview .selected input[type="checkbox"], .umb-listview tr:hover input[type="checkbox"]{display: inline-block !important;} .umb-listview .inactive{color: @grayLight;} 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 index d2dea98f2d..48f443b660 100644 --- 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 @@ -7,14 +7,21 @@ function includePropsPreValsController($rootScope, $scope, localizationService, $scope.propertyAliases = []; $scope.selectedField = null; $scope.systemFields = [ - { value: "updateDate", name: "Last edited" }, - { value: "updater", name: "Updated by" }, - { value: "createDate", name: "Created" }, - { value: "owner", name: "Created by" } + { value: "sortOrder" }, + { value: "updateDate" }, + { value: "updater" }, + { value: "createDate" }, + { value: "owner" }, + { value: "published"}, + { value: "contentTypeAlias" } ]; $scope.getLocalizedKey = function(alias) { switch (alias) { + case "name": + return "general_name"; + case "sortOrder": + return "general_sort"; case "updateDate": return "content_updateDate"; case "updater": @@ -23,6 +30,11 @@ function includePropsPreValsController($rootScope, $scope, localizationService, return "content_createDate"; case "owner": return "content_createBy"; + case "published": + return "content_isPublished"; + case "contentTypeAlias": + //NOTE: This will just be 'Document' type even if it's for media/members since this is just a pre-val editor and we don't have a key for 'Content Type Alias' + return "content_documentType"; } return alias; } @@ -66,7 +78,7 @@ function includePropsPreValsController($rootScope, $scope, localizationService, // 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 movedAlias = $('.alias-value', ui.item).text().trim(); var originalIndex = getAliasIndexByText(movedAlias); // Move the element in the model @@ -114,4 +126,4 @@ function includePropsPreValsController($rootScope, $scope, localizationService, } -angular.module("umbraco").controller("Umbraco.PrevalueEditors.ListViewController", includePropsPreValsController); \ No newline at end of file +angular.module("umbraco").controller("Umbraco.PrevalueEditors.IncludePropertiesListViewController", 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 index 27459ed055..5cf7de7de6 100644 --- 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 @@ -1,8 +1,8 @@ -
+
- - + @@ -26,14 +26,18 @@ - {{val.alias}} + {{val.alias}} {{val.alias}} - + (system field) - + + + Required + + {{val.alias}} 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 4267f30a9e..680923a8f1 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 @@ -10,7 +10,9 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } //Now we need to check if this is for media or content because that will depend on the resources we use + //TODO: Check for members!! var contentResource, contentTypeResource; + if ($scope.model.config.entityType && $scope.model.config.entityType === "media") { contentResource = $injector.get('mediaResource'); contentTypeResource = $injector.get('mediaTypeResource'); @@ -33,8 +35,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific 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: ($scope.model.config.orderBy ? $scope.model.config.orderBy : 'updateDate').trim(), + orderDirection: $scope.model.config.orderDirection ? $scope.model.config.orderDirection.trim() : "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 } @@ -46,8 +48,16 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific //update all of the system includeProperties to enable sorting _.each($scope.options.includeProperties, function(e, i) { + if (e.isSystem) { - e.allowSorting = true; + + //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 + // which requires another join and would be slower. + if (e.alias != "contentTypeAlias") { + e.allowSorting = true; + } + //localize the header var key = getLocalizedKey(e.alias); localizationService.localize(key).then(function (v) { @@ -56,6 +66,10 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }); + $scope.isSortDirection = function (col, direction) { + return $scope.options.orderBy.toUpperCase() == col.toUpperCase() && $scope.options.orderDirection == direction; + } + $scope.next = function() { if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) { $scope.options.pageNumber++; @@ -123,25 +137,6 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }); }; - 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; - } - - return value; - }; - //assign debounce method to the search to limit the queries $scope.search = _.debounce(function() { $scope.options.pageNumber = 1; @@ -285,6 +280,24 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific } }; + 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; + } + + 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) { @@ -295,7 +308,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific // 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']; @@ -319,7 +332,10 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific }; function isDate(val) { - return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); + if (angular.isString(val)) { + return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/); + } + return false; }; //function saveLastPageNumber() { @@ -354,6 +370,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific function getLocalizedKey(alias) { switch (alias) { + case "sortOrder": + return "general_sort"; case "updateDate": return "content_updateDate"; case "updater": @@ -362,6 +380,11 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific 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"; } return alias; } 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 99818bae63..4d4d52f0c1 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 @@ -48,22 +48,22 @@ - + Name - + - + - +
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js new file mode 100644 index 0000000000..a6dc3c28e7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.controller.js @@ -0,0 +1,24 @@ +function sortByPreValsController($rootScope, $scope, localizationService) { + + $scope.sortByFields = [ + { value: "SortOrder", key: "general_sort" }, + { value: "Name", key: "general_name" }, + { value: "UpdateDate", key: "content_updateDate" }, + { value: "Updater", key: "content_updatedBy" }, + { value: "CreateDate", key: "content_createDate" }, + { value: "Owner", key: "content_createBy" }, + { value: "ContentTypeAlias", key: "content_documentType" }, + { value: "Published", key: "content_isPublished" } + ]; + + //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.sortByFields, function (e, i) { + localizationService.localize(e.key).then(function (v) { + e.name = v; + }); + }); + +} + + +angular.module("umbraco").controller("Umbraco.PrevalueEditors.SortByListViewController", sortByPreValsController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.html new file mode 100644 index 0000000000..2b35aa2ca4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/sortby.prevalues.html @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index b034f935b2..d9ef70c026 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -114,6 +114,7 @@ Only alternate types valid for the current location are displayed. + Is Published About this page Alias (how would you describe the picture over the phone) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index a5f687ecfe..506f9000a2 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -117,6 +117,7 @@ Only alternate types valid for the current location are displayed. + Is Published About this page Alias (how would you describe the picture over the phone) diff --git a/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs index aeb4664433..af0463136d 100644 --- a/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs @@ -24,11 +24,12 @@ namespace Umbraco.Web.PropertyEditors return new Dictionary { {"pageSize", "10"}, - {"orderBy", "SortOrder"}, + {"orderBy", "sortOrder"}, {"orderDirection", "asc"}, { "includeProperties", new[] { + new {alias = "sortOrder", header = "Sort order", isSystem = 1}, new {alias = "updateDate", header = "Last edited", isSystem = 1}, new {alias = "updater", header = "Last edited by", isSystem = 1} } @@ -43,10 +44,10 @@ namespace Umbraco.Web.PropertyEditors [PreValueField("pageSize", "Page Size", "number", Description = "Number of items per page")] public int PageSize { get; set; } - [PreValueField("orderBy", "Order By", "textstring", Description = "SortOrder, Name, UpdateDate, CreateDate, ContentTypeAlias, UpdateDate, Updater or Owner")] + [PreValueField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html")] public int OrderBy { get; set; } - [PreValueField("orderDirection", "Order By", "views/propertyeditors/listview/orderdirection.prevalues.html")] + [PreValueField("orderDirection", "Order Direction", "views/propertyeditors/listview/orderdirection.prevalues.html")] public int OrderDirection { get; set; } [PreValueField("includeProperties", "Include Properties", "views/propertyeditors/listview/includeproperties.prevalues.html")]