List view config complete: U4-4972 Make list view configurable,

This commit is contained in:
Shannon
2014-09-15 19:01:28 +10:00
parent 96d570e760
commit b38acdd654
13 changed files with 178 additions and 114 deletions

View File

@@ -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<IContent> ProcessQuery(Sql sql)
{
//NOTE: This doesn't allow properties to be part of the query

View File

@@ -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";
}
}
/// <summary>

View File

@@ -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;
}
}
}
}

View File

@@ -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;}

View File

@@ -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);
angular.module("umbraco").controller("Umbraco.PrevalueEditors.IncludePropertiesListViewController", includePropsPreValsController);

View File

@@ -1,8 +1,8 @@
<div class="umb-editor" ng-controller="Umbraco.PrevalueEditors.ListViewController">
<div class="umb-editor" ng-controller="Umbraco.PrevalueEditors.IncludePropertiesListViewController">
<div class="control-group">
<select ng-model="selectedField">
<option ng-repeat="field in systemFields" value="_system_{{field.value}}">{{field.name}}</option>
<select ng-model="selectedField">
<option ng-repeat="field in systemFields" value="_system_{{field.value}}">{{field.name}}</option>
<option class="select-dash" disabled="disabled">----</option>
<option ng-repeat="alias in propertyAliases" value="{{alias}}">{{alias}}</option>
</select>
@@ -26,14 +26,18 @@
<i class="icon icon-navigation handle"></i>
</td>
<td>
<span class="alias-value" ng-if="!val.isSystem">{{val.alias}}</span>
<span class="alias-value" ng-if="!val.isSystem">{{val.alias}}</span>
<span class="alias-value" ng-if="val.isSystem == 1">
{{val.alias}}
</span>
</span>
<em ng-show="val.isSystem == 1"><small>(system field)</small></em>
</td>
<td>
<input type="text" ng-model="val.header" ng-if="!val.isSystem" />
<ng-form name="headerForm" ng-if="!val.isSystem">
<input type="text" name="header" ng-model="val.header" required />
<span class="help-inline" val-msg-for="header" val-toggle-msg="required">Required</span>
</ng-form>
<span ng-if="val.isSystem">
<localize key="{{getLocalizedKey(val.alias)}}">{{val.alias}}</localize>
</span>

View File

@@ -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;
}

View File

@@ -48,22 +48,22 @@
<input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()">
</td>
<td>
<a href="#" ng-click="sort('Name', true)" prevent-default>
<a href="#" ng-click="sort('Name', true)" prevent-default class="sortable">
<localize key="general_name">Name</localize>
<i class="icon-sort"></i>
<i class="icon" ng-class="{'icon-navigation-down': isSortDirection('Name', 'asc'), 'icon-navigation-up': isSortDirection('Name', 'desc')}"></i>
</a>
</td>
<td ng-repeat="column in options.includeProperties">
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'no-sort':!column.allowSorting}" prevent-default>
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'sortable':column.allowSorting}" prevent-default>
<span ng-bind="column.header"></span>
<i class="icon-sort"></i>
<i class="icon" ng-class="{'icon-navigation-down': isSortDirection(column.alias, 'asc'), 'icon-navigation-up': isSortDirection(column.alias, 'desc')}"></i>
</a>
</td>
<td>
<form class="pull-right" novalidate>
<i class="icon-search"></i>
<i class="icon-search" ng-click="search()"></i>
<input type="text" ng-model="options.filter" on-keyup="search()" no-dirty-check>
</form>
</td>

View File

@@ -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);

View File

@@ -0,0 +1,5 @@
<select ng-model="model.value"
ng-controller="Umbraco.PrevalueEditors.SortByListViewController"
ng-options="field.value as field.name for field in sortByFields">
</select>

View File

@@ -114,6 +114,7 @@
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
</area>
<area alias="content">
<key alias="isPublished" version="7.2">Is Published</key>
<key alias="about">About this page</key>
<key alias="alias">Alias</key>
<key alias="alternativeTextHelp">(how would you describe the picture over the phone)</key>

View File

@@ -117,6 +117,7 @@
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
</area>
<area alias="content">
<key alias="isPublished" version="7.2">Is Published</key>
<key alias="about">About this page</key>
<key alias="alias">Alias</key>
<key alias="alternativeTextHelp">(how would you describe the picture over the phone)</key>

View File

@@ -24,11 +24,12 @@ namespace Umbraco.Web.PropertyEditors
return new Dictionary<string, object>
{
{"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")]