diff --git a/src/UI/Mixins/AsFilteredCollection.js b/src/UI/Mixins/AsFilteredCollection.js new file mode 100644 index 000000000..447f60edb --- /dev/null +++ b/src/UI/Mixins/AsFilteredCollection.js @@ -0,0 +1,78 @@ +'use strict'; + +define( + [ + 'underscore', + 'backbone'], + function (_, Backbone) { + + return function () { + + this.prototype.setFilter = function(filter, options) { + options = _.extend({ reset: true }, options || {}); + + this.state.filterKey = filter[0]; + this.state.filterValue = filter[1]; + + if (options.reset) { + if (this.mode != 'server') { + this.fullCollection.resetFiltered(); + } else { + return this.fetch(); + } + } + }; + + this.prototype.setFilterMode = function(mode, options) { + this.setFilter(this.filterModes[mode], options); + }; + + var originalMakeFullCollection = this.prototype._makeFullCollection; + + this.prototype._makeFullCollection = function (models, options) { + var self = this; + + self.shadowCollection = originalMakeFullCollection.apply(this, [models, options]); + + var filterModel = function(model) { + if (!self.state.filterKey || !self.state.filterValue) + return true; + else + return model.get(self.state.filterKey) === self.state.filterValue; + }; + + self.shadowCollection.filtered = function() { + return this.filter(filterModel); + }; + + var filteredModels = self.shadowCollection.filtered(); + + var fullCollection = originalMakeFullCollection.apply(this, [filteredModels, options]); + + + fullCollection.resetFiltered = function(options) { + Backbone.Collection.prototype.reset.apply(this, [self.shadowCollection.filtered(), options]); + }; + + fullCollection.reset = function (models, options) { + self.shadowCollection.reset(models, options); + self.fullCollection.resetFiltered(); + }; + + return fullCollection; + }; + + _.extend(this.prototype.state, { + filterKey : null, + filterValue : null + }); + + _.extend(this.prototype.queryParams, { + filterKey : 'filterKey', + filterValue : 'filterValue' + }); + + return this; + }; + } +); \ No newline at end of file diff --git a/src/UI/Mixins/AsPersistedStateCollection.js b/src/UI/Mixins/AsPersistedStateCollection.js index 879c05427..d4177f1a4 100644 --- a/src/UI/Mixins/AsPersistedStateCollection.js +++ b/src/UI/Mixins/AsPersistedStateCollection.js @@ -62,23 +62,20 @@ define( return '1'; }; - - _.extend(this.prototype, { - initialSort: function () { - var key = this.state.sortKey; - var order = this.state.order; - - if (this[key] && this.mode === 'client') { - var sortValue = this[key]; - - this.setSorting(key, order, { sortValue: sortValue }); - - var comparator = this._makeComparator(key, order, sortValue); - this.fullCollection.comparator = comparator; - this.fullCollection.sort(); - } - } - }); + + 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; }; diff --git a/src/UI/Series/Index/SeriesIndexLayout.js b/src/UI/Series/Index/SeriesIndexLayout.js index 416d1ec1a..ff7eb55c1 100644 --- a/src/UI/Series/Index/SeriesIndexLayout.js +++ b/src/UI/Series/Index/SeriesIndexLayout.js @@ -167,6 +167,44 @@ define( this.listenTo(SeriesCollection, 'sync', this._renderView); this.listenTo(SeriesCollection, 'remove', this._renderView); + this.filteringOptions = { + type : 'radio', + storeState : true, + menuKey : 'series.filterMode', + defaultAction: 'all', + items : + [ + { + key : 'all', + title : '', + tooltip : 'All', + icon : 'icon-circle-blank', + callback: this._setFilter + }, + { + key : 'monitored', + title : '', + tooltip : 'Monitored Only', + icon : 'icon-nd-monitored', + callback: this._setFilter + }, + { + key : 'continuing', + title : '', + tooltip : 'Continuing Only', + icon : 'icon-play', + callback: this._setFilter + }, + { + key : 'ended', + title : '', + tooltip : 'Ended Only', + icon : 'icon-stop', + callback: this._setFilter + } + ] + }; + this.viewButtons = { type : 'radio', storeState : true, @@ -201,26 +239,30 @@ define( _showTable: function () { this.currentView = new Backgrid.Grid({ - collection: SeriesCollection, + collection: this.seriesCollection, columns : this.columns, className : 'table table-hover' }); - this._fetchCollection(); + this._renderView(); }, _showList: function () { - this.currentView = new ListCollectionView({ collection: SeriesCollection }); + this.currentView = new ListCollectionView({ + collection: this.seriesCollection + }); - this._fetchCollection(); + this._renderView(); }, _showPosters: function () { - this.currentView = new PosterCollectionView({ collection: SeriesCollection }); + this.currentView = new PosterCollectionView({ + collection: this.seriesCollection + }); - this._fetchCollection(); + this._renderView(); }, - + _renderView: function () { if (SeriesCollection.length === 0) { @@ -238,10 +280,17 @@ define( onShow: function () { this._showToolbar(); this._renderView(); + this._fetchCollection(); }, _fetchCollection: function () { - SeriesCollection.fetch(); + this.seriesCollection.fetch(); + }, + + _setFilter: function(buttonContext) { + var mode = buttonContext.model.get('key'); + + this.seriesCollection.setFilterMode(mode); }, _showToolbar: function () { @@ -251,11 +300,11 @@ define( } var rightButtons = [ + this.sortingOptions, + this.filteringOptions, this.viewButtons ]; - rightButtons.splice(0, 0, this.sortingOptions); - this.toolbar.show(new ToolbarLayout({ right : rightButtons, left : diff --git a/src/UI/Series/SeriesCollection.js b/src/UI/Series/SeriesCollection.js index 629ed799e..4f00e6c42 100644 --- a/src/UI/Series/SeriesCollection.js +++ b/src/UI/Series/SeriesCollection.js @@ -6,9 +6,10 @@ define( 'backbone.pageable', 'Series/SeriesModel', 'api!series', + 'Mixins/AsFilteredCollection', 'Mixins/AsPersistedStateCollection', 'moment' - ], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsPersistedStateCollection, Moment) { + ], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsPersistedStateCollection, Moment) { var Collection = PageableCollection.extend({ url : window.NzbDrone.ApiRoot + '/series', model: SeriesModel, @@ -47,6 +48,14 @@ define( return proxy.save(); }, + // Filter Modes + filterModes: { + 'all' : [null, null], + 'continuing' : ['status', 'continuing'], + 'ended' : ['status', 'ended'], + 'monitored' : ['monitored', true] + }, + //Sorters nextAiring: function (model, attr) { var nextAiring = model.get(attr); @@ -59,9 +68,9 @@ define( } }); - var MixedIn = AsPersistedStateCollection.call(Collection); - var collection = new MixedIn(SeriesData); - collection.initialSort(); + var FilteredCollection = AsFilteredCollection.call(Collection); + var MixedIn = AsPersistedStateCollection.call(FilteredCollection); + var collection = new MixedIn(SeriesData, { full: true }); return collection; }); diff --git a/src/UI/Shared/Toolbar/Radio/RadioButtonView.js b/src/UI/Shared/Toolbar/Radio/RadioButtonView.js index 1fb788250..baa67a5da 100644 --- a/src/UI/Shared/Toolbar/Radio/RadioButtonView.js +++ b/src/UI/Shared/Toolbar/Radio/RadioButtonView.js @@ -9,6 +9,10 @@ define( template : 'Shared/Toolbar/ButtonTemplate', className: 'btn', + ui: { + icon: 'i' + }, + events: { 'click': 'onClick' }, @@ -49,7 +53,7 @@ define( var callback = this.model.get('callback'); if (callback) { - callback.call(this.model.ownerContext); + callback.call(this.model.ownerContext, this); } } }); diff --git a/src/UI/Shared/Toolbar/ToolbarLayout.js b/src/UI/Shared/Toolbar/ToolbarLayout.js index 8a907dad6..a50828880 100644 --- a/src/UI/Shared/Toolbar/ToolbarLayout.js +++ b/src/UI/Shared/Toolbar/ToolbarLayout.js @@ -12,11 +12,9 @@ define( return Marionette.Layout.extend({ template: 'Shared/Toolbar/ToolbarLayoutTemplate', - regions: { - left_1 : '.x-toolbar-left-1', - left_2 : '.x-toolbar-left-2', - right_1: '.x-toolbar-right-1', - right_2: '.x-toolbar-right-2' + ui: { + left_x : '.x-toolbar-left', + right_x: '.x-toolbar-right' }, initialize: function (options) { @@ -97,8 +95,17 @@ define( break; } } - - this[position + '_' + (index + 1).toString()].show(buttonGroupView); + + var regionId = position + "_" + (index + 1); + var region = this[regionId]; + + if (!region) { + var regionClassName = "x-toolbar-" + position + "-" + (index + 1); + this.ui[position + '_x'].append('
\r\n'); + region = this.addRegion(regionId, "." + regionClassName); + } + + region.show(buttonGroupView); } }); }); diff --git a/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html b/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html index b4cd4dcda..533f83bf9 100644 --- a/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html +++ b/src/UI/Shared/Toolbar/ToolbarLayoutTemplate.html @@ -1,8 +1,2 @@ -
-
-
-
-
-
-
-
+
+