Updated sorting architecture so the collections can specify the sort-oddities instead of in backgrid column definitions.

This commit is contained in:
Taloth Saldono 2014-07-04 22:07:03 +02:00
parent 2b6f908038
commit 6941888832
20 changed files with 173 additions and 186 deletions

View File

@ -25,12 +25,6 @@ namespace NzbDrone.Api.Blacklist
SortDirection = pagingResource.SortDirection SortDirection = pagingResource.SortDirection
}; };
//This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue
if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase))
{
pagingSpec.SortKey = "series.sortTitle";
}
return ApplyToPage(_blacklistService.Paged, pagingSpec); return ApplyToPage(_blacklistService.Paged, pagingSpec);
} }

View File

@ -33,12 +33,6 @@ namespace NzbDrone.Api.History
SortDirection = pagingResource.SortDirection SortDirection = pagingResource.SortDirection
}; };
//This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue
if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase))
{
pagingSpec.SortKey = "series.sortTitle";
}
if (pagingResource.FilterKey == "eventType") if (pagingResource.FilterKey == "eventType")
{ {
var filterValue = (HistoryEventType)Convert.ToInt32(pagingResource.FilterValue); var filterValue = (HistoryEventType)Convert.ToInt32(pagingResource.FilterValue);

View File

@ -31,12 +31,6 @@ namespace NzbDrone.Api.Wanted
SortDirection = pagingResource.SortDirection SortDirection = pagingResource.SortDirection
}; };
//This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue
if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase))
{
pagingSpec.SortKey = "series.sortTitle";
}
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false") if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
{ {
pagingSpec.FilterExpression = v => v.Monitored == false || v.Series.Monitored == false; pagingSpec.FilterExpression = v => v.Monitored == false || v.Series.Monitored == false;

View File

@ -31,12 +31,6 @@ namespace NzbDrone.Api.Wanted
SortDirection = pagingResource.SortDirection SortDirection = pagingResource.SortDirection
}; };
//This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue
if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase))
{
pagingSpec.SortKey = "series.sortTitle";
}
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false") if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
{ {
pagingSpec.FilterExpression = v => v.Monitored == false || v.Series.Monitored == false; pagingSpec.FilterExpression = v => v.Monitored == false || v.Series.Monitored == false;

View File

@ -3,9 +3,10 @@ define(
[ [
'History/Blacklist/BlacklistModel', 'History/Blacklist/BlacklistModel',
'backbone.pageable', 'backbone.pageable',
'Mixins/AsSortedCollection',
'Mixins/AsPersistedStateCollection' 'Mixins/AsPersistedStateCollection'
], function (BlacklistModel, PageableCollection, AsPersistedStateCollection) { ], function (BlacklistModel, PageableCollection, AsSortedCollection, AsPersistedStateCollection) {
var collection = PageableCollection.extend({ var Collection = PageableCollection.extend({
url : window.NzbDrone.ApiRoot + '/blacklist', url : window.NzbDrone.ApiRoot + '/blacklist',
model: BlacklistModel, model: BlacklistModel,
@ -27,6 +28,10 @@ define(
} }
}, },
sortMappings: {
'series' : { sortKey: 'series.sortTitle' }
},
parseState: function (resp) { parseState: function (resp) {
return { totalRecords: resp.totalRecords }; return { totalRecords: resp.totalRecords };
}, },
@ -40,5 +45,6 @@ define(
} }
}); });
return AsPersistedStateCollection.apply(collection); Collection = AsSortedCollection.call(Collection);
return AsPersistedStateCollection.call(Collection);
}); });

View File

@ -37,14 +37,12 @@ define(
{ {
name : 'series', name : 'series',
label : 'Series', label : 'Series',
cell : SeriesTitleCell, cell : SeriesTitleCell
sortValue : 'series.sortTitle'
}, },
{ {
name : 'sourceTitle', name : 'sourceTitle',
label : 'Source Title', label : 'Source Title',
cell : 'string', cell : 'string'
sortValue : 'sourceTitle'
}, },
{ {
name : 'quality', name : 'quality',

View File

@ -4,9 +4,10 @@ define(
'History/HistoryModel', 'History/HistoryModel',
'backbone.pageable', 'backbone.pageable',
'Mixins/AsFilteredCollection', 'Mixins/AsFilteredCollection',
'Mixins/AsSortedCollection',
'Mixins/AsPersistedStateCollection' 'Mixins/AsPersistedStateCollection'
], function (HistoryModel, PageableCollection, AsFilteredCollection, AsPersistedStateCollection) { ], function (HistoryModel, PageableCollection, AsFilteredCollection, AsSortedCollection, AsPersistedStateCollection) {
var collection = PageableCollection.extend({ var Collection = PageableCollection.extend({
url : window.NzbDrone.ApiRoot + '/history', url : window.NzbDrone.ApiRoot + '/history',
model: HistoryModel, model: HistoryModel,
@ -35,6 +36,10 @@ define(
'failed' : ['eventType', '4'] 'failed' : ['eventType', '4']
}, },
sortMappings: {
'series' : { sortKey: 'series.sortTitle' }
},
initialize: function (options) { initialize: function (options) {
delete this.queryParams.episodeId; delete this.queryParams.episodeId;
@ -58,6 +63,7 @@ define(
} }
}); });
collection = AsFilteredCollection.call(collection); Collection = AsFilteredCollection.call(Collection);
return AsPersistedStateCollection.call(collection); Collection = AsSortedCollection.call(Collection);
return AsPersistedStateCollection.call(Collection);
}); });

View File

@ -47,8 +47,7 @@ define(
{ {
name : 'series', name : 'series',
label : 'Series', label : 'Series',
cell : SeriesTitleCell, cell : SeriesTitleCell
sortValue : 'series.sortTitle'
}, },
{ {
name : 'episode', name : 'episode',

View File

@ -7,7 +7,6 @@ define(
return function () { return function () {
var originalInit = this.prototype.initialize; var originalInit = this.prototype.initialize;
this.prototype.initialize = function (options) { this.prototype.initialize = function (options) {
options = options || {}; options = options || {};
@ -30,18 +29,24 @@ define(
} }
}; };
if (!this.prototype._getSortMapping) {
this.prototype._getSortMapping = function(key) {
return { name: key, sortKey: key };
};
}
var _setInitialState = function () { var _setInitialState = function () {
var key = Config.getValue('{0}.sortKey'.format(this.tableName), this.state.sortKey); var key = Config.getValue('{0}.sortKey'.format(this.tableName), this.state.sortKey);
var direction = Config.getValue('{0}.sortDirection'.format(this.tableName), this.state.order); var direction = Config.getValue('{0}.sortDirection'.format(this.tableName), this.state.order);
var order = parseInt(direction, 10); var order = parseInt(direction, 10);
this.state.sortKey = key; this.state.sortKey = this._getSortMapping(key).sortKey;
this.state.order = order; this.state.order = order;
}; };
var _storeStateFromBackgrid = function (column, sortDirection) { var _storeStateFromBackgrid = function (column, sortDirection) {
var order = _convertDirectionToInt(sortDirection); var order = _convertDirectionToInt(sortDirection);
var sortKey = column.has('sortValue') && _.isString(column.get('sortValue')) ? column.get('sortValue') : column.get('name'); var sortKey = this._getSortMapping(column.get('name')).sortKey;
Config.setValue('{0}.sortKey'.format(this.tableName), sortKey); Config.setValue('{0}.sortKey'.format(this.tableName), sortKey);
Config.setValue('{0}.sortDirection'.format(this.tableName), order); Config.setValue('{0}.sortDirection'.format(this.tableName), order);
@ -49,7 +54,7 @@ define(
var _storeState = function (sortModel, sortDirection) { var _storeState = function (sortModel, sortDirection) {
var order = _convertDirectionToInt(sortDirection); var order = _convertDirectionToInt(sortDirection);
var sortKey = sortModel.get('name'); var sortKey = this._getSortMapping(sortModel.get('name')).sortKey;
Config.setValue('{0}.sortKey'.format(this.tableName), sortKey); Config.setValue('{0}.sortKey'.format(this.tableName), sortKey);
Config.setValue('{0}.sortDirection'.format(this.tableName), order); Config.setValue('{0}.sortDirection'.format(this.tableName), order);
@ -63,20 +68,6 @@ define(
return '1'; return '1';
}; };
var originalMakeComparator = this.prototype._makeComparator;
this.prototype._makeComparator = function (sortKey, order, sortValue) {
var state = this.state;
sortKey = sortKey || state.sortKey;
order = order || state.order;
if (!sortKey || !order) return;
if (!sortValue && this[sortKey]) sortValue = this[sortKey];
return originalMakeComparator.call(this, sortKey, order, sortValue);
};
return this; return this;
}; };
} }

View File

@ -0,0 +1,45 @@
'use strict';
define(
['underscore', 'Config'],
function (_, Config) {
return function () {
this.prototype._getSortMappings = function () {
var result = {};
if (this.sortMappings) {
_.each(this.sortMappings, function (values, key) {
var item = {
name: key,
sortKey: values.sortKey || key,
sortValue: values.sortValue
};
result[key] = item;
result[item.sortKey] = item;
});
}
return result;
};
this.prototype._getSortMapping = function (key) {
var sortMappings = this._getSortMappings();
return sortMappings[key] || { name: key, sortKey: key };
};
var originalSetSorting = this.prototype.setSorting;
this.prototype.setSorting = function (sortKey, order, options) {
var sortMapping = this._getSortMapping(sortKey);
options = _.defaults({ sortValue: sortMapping.sortValue }, options || {});
return originalSetSorting.call(this, sortMapping.sortKey, order, options);
};
return this;
};
}
);

View File

@ -60,8 +60,7 @@ define(
name : 'title', name : 'title',
label : 'Title', label : 'Title',
cell : SeriesTitleCell, cell : SeriesTitleCell,
cellValue : 'this', cellValue : 'this'
sortValue : 'sortTitle'
}, },
{ {
name : 'qualityProfileId', name : 'qualityProfileId',

View File

@ -77,8 +77,7 @@ define(
{ {
name : 'nextAiring', name : 'nextAiring',
label : 'Next Airing', label : 'Next Airing',
cell : RelativeDateCell, cell : RelativeDateCell
sortValue : SeriesCollection.nextAiring
}, },
{ {
name : 'percentOfEpisodes', name : 'percentOfEpisodes',
@ -174,8 +173,7 @@ define(
}, },
{ {
title: 'Next Airing', title: 'Next Airing',
name : 'nextAiring', name : 'nextAiring'
sortValue : SeriesCollection.nextAiring
}, },
{ {
title: 'Episodes', title: 'Episodes',

View File

@ -7,16 +7,17 @@ define(
'Series/SeriesModel', 'Series/SeriesModel',
'api!series', 'api!series',
'Mixins/AsFilteredCollection', 'Mixins/AsFilteredCollection',
'Mixins/AsSortedCollection',
'Mixins/AsPersistedStateCollection', 'Mixins/AsPersistedStateCollection',
'moment' 'moment'
], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsPersistedStateCollection, Moment) { ], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsSortedCollection, AsPersistedStateCollection, Moment) {
var Collection = PageableCollection.extend({ var Collection = PageableCollection.extend({
url : window.NzbDrone.ApiRoot + '/series', url : window.NzbDrone.ApiRoot + '/series',
model: SeriesModel, model: SeriesModel,
tableName: 'series', tableName: 'series',
state: { state: {
sortKey: 'title', sortKey: 'sortTitle',
order : -1, order : -1,
pageSize: 100000 pageSize: 100000
}, },
@ -56,8 +57,9 @@ define(
'monitored' : ['monitored', true] 'monitored' : ['monitored', true]
}, },
//Sorters sortMappings: {
nextAiring: function (model, attr) { 'title' : { sortKey: 'sortTitle' },
'nextAiring' : { sortValue: function (model, attr) {
var nextAiring = model.get(attr); var nextAiring = model.get(attr);
if (nextAiring) { if (nextAiring) {
@ -72,11 +74,13 @@ define(
return Number.MAX_VALUE; return Number.MAX_VALUE;
} }
}
}
}); });
var FilteredCollection = AsFilteredCollection.call(Collection); Collection = AsFilteredCollection.call(Collection);
var MixedIn = AsPersistedStateCollection.call(FilteredCollection); Collection = AsSortedCollection.call(Collection);
var collection = new MixedIn(SeriesData, { full: true }); Collection = AsPersistedStateCollection.call(Collection);
return collection; return new Collection(SeriesData, { full: true });
}); });

View File

@ -39,13 +39,12 @@ define(
this.direction(column.get('direction')); this.direction(column.get('direction'));
if (this.collection.state) { if (this.collection.state) {
var key = this.collection.state.sortKey; var name = this._getSortMapping().name;
var order = this.collection.state.order; var order = this.collection.state.order;
if (key === this.column.get('name')) { if (name === column.get('name')) {
this._setSortIcon(order); this._setSortIcon(order);
} }
else { else {
this._removeSortIcon(); this._removeSortIcon();
} }
@ -69,10 +68,10 @@ define(
var columnDirection = this.column.get('direction'); var columnDirection = this.column.get('direction');
if (!columnDirection && this.collection.state) { if (!columnDirection && this.collection.state) {
var key = this.collection.state.sortKey; var name = this._getSortMapping().name;
var order = this.collection.state.order; var order = this.collection.state.order;
if (key === this.column.get('name')) { if (name === this.column.get('name')) {
columnDirection = order; columnDirection = order;
} }
} }
@ -80,31 +79,41 @@ define(
return columnDirection; return columnDirection;
}, },
_getSortMapping: function() {
var sortKey = this.collection.state.sortKey;
if (this.collection._getSortMapping) {
return this.collection._getSortMapping(sortKey);
}
return { name: sortKey, sortKey: sortKey };
},
onClick: function (e) { onClick: function (e) {
e.preventDefault(); e.preventDefault();
var collection = this.collection; var collection = this.collection;
var event = 'backgrid:sort'; var event = 'backgrid:sort';
function toggleSort(header, col) { var column = this.column;
collection.state.sortKey = col.get('name'); var sortable = Backgrid.callByNeed(column.sortable(), column, collection);
var direction = header.direction(); if (sortable) {
if (direction === 'ascending' || direction === -1) var direction = collection.state.order;
{ if (direction === 'ascending' || direction === -1) {
collection.state.order = 'descending'; direction = 'descending';
collection.trigger(event, col, 'descending');
}
else
{
collection.state.order = 'ascending';
collection.trigger(event, col, 'ascending');
} }
else {
direction = 'ascending';
} }
var column = this.column; if (collection.setSorting) {
var sortable = Backgrid.callByNeed(column.sortable(), column, this.collection); collection.setSorting(column.get('name'), direction);
if (sortable) { }
toggleSort(this, column); else {
collection.state.sortKey = column.get('name');
collection.state.order = direction;
}
collection.trigger(event, column, direction);
} }
}, },

View File

@ -10,20 +10,6 @@ define(
'title' : '', 'title' : '',
'active' : false, 'active' : false,
'tooltip': undefined 'tooltip': undefined
},
sortValue: function () {
var sortValue = this.get('sortValue');
if (_.isString(sortValue)) {
return this[sortValue];
}
else if (_.isFunction(sortValue)) {
return sortValue;
}
return function (model, colName) {
return model.get(colName);
};
} }
}); });
}); });

View File

@ -35,51 +35,10 @@ define(
order = null; order = null;
} }
var comparator = this.makeComparator(sortModel.get('name'), order, collection.setSorting(sortModel.get('name'), order);
order ?
sortModel.sortValue() :
function (model) {
return model.cid;
});
if (PageableCollection &&
collection instanceof PageableCollection) {
collection.setSorting(order && sortModel.get('name'), order,
{sortValue: sortModel.sortValue()});
if (collection.mode === 'client') {
if (collection.fullCollection.comparator === null) {
collection.fullCollection.comparator = comparator;
}
collection.fullCollection.sort(); collection.fullCollection.sort();
}
else {
collection.fetch({reset: true});
}
}
else {
collection.comparator = comparator;
collection.sort();
}
return this; return this;
},
makeComparator: function (attr, order, func) {
return function (left, right) {
// extract the values from the models
var l = func(left, attr), r = func(right, attr), t;
// if descending order, swap left and right
if (order === 1) t = l, l = r, r = t;
// compare as usual
if (l === r) return 0;
else if (l < r) return -1;
return 1;
};
} }
}); });
}); });

View File

@ -26,13 +26,13 @@ define(
onRender: function () { onRender: function () {
if (this.viewCollection.state) { if (this.viewCollection.state) {
var key = this.viewCollection.state.sortKey; var sortKey = this.viewCollection.state.sortKey;
var name = this.viewCollection._getSortMapping(sortKey).name;
var order = this.viewCollection.state.order; var order = this.viewCollection.state.order;
if (key === this.model.get('name')) { if (name === this.model.get('name')) {
this._setSortIcon(order); this._setSortIcon(order);
} }
else { else {
this._removeSortIcon(); this._removeSortIcon();
} }
@ -45,19 +45,16 @@ define(
var collection = this.viewCollection; var collection = this.viewCollection;
var event = 'drone:sort'; var event = 'drone:sort';
collection.state.sortKey = this.model.get('name');
var direction = collection.state.order; var direction = collection.state.order;
if (direction === 'ascending' || direction === -1) {
direction = 'descending';
}
else {
direction = 'ascending';
}
if (direction === 'ascending' || direction === -1) collection.setSorting(this.model.get('name'), direction);
{ collection.trigger(event, this.model, direction);
collection.state.order = 'descending';
collection.trigger(event, this.model, 'descending');
}
else
{
collection.state.order = 'ascending';
collection.trigger(event, this.model, 'ascending');
}
}, },
_convertDirectionToIcon: function (dir) { _convertDirectionToIcon: function (dir) {

View File

@ -38,12 +38,14 @@ define(
{ {
name : 'filename', name : 'filename',
label: 'Filename', label: 'Filename',
cell : FilenameCell cell : FilenameCell,
sortable: false
}, },
{ {
name : 'lastWriteTime', name : 'lastWriteTime',
label: 'Last Write Time', label: 'Last Write Time',
cell : RelativeDateCell cell : RelativeDateCell,
sortable: false
}, },
{ {
name : 'downloadUrl', name : 'downloadUrl',

View File

@ -5,9 +5,10 @@ define(
'Series/EpisodeModel', 'Series/EpisodeModel',
'backbone.pageable', 'backbone.pageable',
'Mixins/AsFilteredCollection', 'Mixins/AsFilteredCollection',
'Mixins/AsSortedCollection',
'Mixins/AsPersistedStateCollection' 'Mixins/AsPersistedStateCollection'
], function (_, EpisodeModel, PagableCollection, AsFilteredCollection, AsPersistedStateCollection) { ], function (_, EpisodeModel, PagableCollection, AsFilteredCollection, AsSortedCollection, AsPersistedStateCollection) {
var collection = PagableCollection.extend({ var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/wanted/cutoff', url : window.NzbDrone.ApiRoot + '/wanted/cutoff',
model: EpisodeModel, model: EpisodeModel,
tableName: 'wanted.cutoff', tableName: 'wanted.cutoff',
@ -36,6 +37,10 @@ define(
'unmonitored' : ['monitored', 'false'], 'unmonitored' : ['monitored', 'false'],
}, },
sortMappings: {
'series' : { sortKey: 'series.sortTitle' }
},
parseState: function (resp) { parseState: function (resp) {
return {totalRecords: resp.totalRecords}; return {totalRecords: resp.totalRecords};
}, },
@ -49,6 +54,7 @@ define(
} }
}); });
collection = AsFilteredCollection.call(collection); Collection = AsFilteredCollection.call(Collection);
return AsPersistedStateCollection.call(collection); Collection = AsSortedCollection.call(Collection);
return AsPersistedStateCollection.call(Collection);
}); });

View File

@ -5,9 +5,10 @@ define(
'Series/EpisodeModel', 'Series/EpisodeModel',
'backbone.pageable', 'backbone.pageable',
'Mixins/AsFilteredCollection', 'Mixins/AsFilteredCollection',
'Mixins/AsSortedCollection',
'Mixins/AsPersistedStateCollection' 'Mixins/AsPersistedStateCollection'
], function (_, EpisodeModel, PagableCollection, AsFilteredCollection, AsPersistedStateCollection) { ], function (_, EpisodeModel, PagableCollection, AsFilteredCollection, AsSortedCollection, AsPersistedStateCollection) {
var collection = PagableCollection.extend({ var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/wanted/missing', url : window.NzbDrone.ApiRoot + '/wanted/missing',
model: EpisodeModel, model: EpisodeModel,
tableName: 'wanted.missing', tableName: 'wanted.missing',
@ -35,6 +36,10 @@ define(
'unmonitored' : ['monitored', 'false'] 'unmonitored' : ['monitored', 'false']
}, },
sortMappings: {
'series' : { sortKey: 'series.sortTitle' }
},
parseState: function (resp) { parseState: function (resp) {
return {totalRecords: resp.totalRecords}; return {totalRecords: resp.totalRecords};
}, },
@ -48,6 +53,7 @@ define(
} }
}); });
collection = AsFilteredCollection.call(collection); Collection = AsFilteredCollection.call(Collection);
return AsPersistedStateCollection.call(collection); Collection = AsSortedCollection.call(Collection);
return AsPersistedStateCollection.call(Collection);
}); });