List view config complete: U4-4972 Make list view configurable,
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;}
|
||||
|
||||
@@ -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);
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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")]
|
||||
|
||||
Reference in New Issue
Block a user