Backgrid added

This commit is contained in:
Mark McDowall 2013-04-22 17:35:04 -07:00
parent 2b5f208126
commit d706a35ab7
18 changed files with 2447 additions and 1492 deletions

View File

@ -22,8 +22,8 @@ module.exports = function (grunt) {
'UI/JsLibraries/require.js' : 'http://raw.github.com/jrburke/requirejs/master/require.js',
'UI/JsLibraries/sugar.js' : 'http://raw.github.com/andrewplummer/Sugar/master/release/sugar-full.development.js',
'UI/JsLibraries/underscore.js' : 'http://underscorejs.org/underscore.js',
'UI/JsLibraries/backbone-pageable.js' : 'https://raw.github.com/wyuenho/backbone-pageable/master/lib/backbone-pageable.js',
'UI/JsLibraries/backgrid.js' : 'https://raw.github.com/wyuenho/backbone-pageable/master/lib/backbone-pageable.js'
'UI/JsLibraries/backbone.pageable.js' : 'https://raw.github.com/wyuenho/backbone-pageable/master/lib/backbone-pageable.js',
'UI/JsLibraries/backbone.backgrid.js' : 'https://raw.github.com/wyuenho/backgrid/master/lib/backgrid.js'
},
uglify: {

View File

@ -1,6 +1,6 @@
"use strict";
define(['app', 'Shared/ModalRegion', 'AddSeries/AddSeriesLayout',
'Series/Index/SeriesIndexCollectionView', 'Upcoming/UpcomingCollectionView',
'Series/Index/SeriesIndexLayout', 'Upcoming/UpcomingCollectionView',
'Calendar/CalendarCollectionView', 'Shared/NotificationView',
'Shared/NotFoundView', 'MainMenuView',
'Series/Details/SeriesDetailsView', 'Series/EpisodeCollection',
@ -11,7 +11,7 @@ define(['app', 'Shared/ModalRegion', 'AddSeries/AddSeriesLayout',
series: function () {
this._setTitle('NzbDrone');
NzbDrone.mainRegion.show(new NzbDrone.Series.Index.SeriesIndexCollectionView());
NzbDrone.mainRegion.show(new NzbDrone.Series.Index.SeriesIndexLayout());
},
seriesDetails: function (query) {

View File

@ -89,7 +89,7 @@
<script src="/JsLibraries/backbone.mutators.js"></script>
<script src="/JsLibraries/backbone.marionette.js"></script>
<script src="/JsLibraries/backbone.pageable.js"></script>
<script src="/JsLibraries/backgrid.js"></script>
<script src="/JsLibraries/backbone.backgrid.js"></script>
<script src="/JsLibraries/jquery.tablesorter.js"></script>
<script src="/JsLibraries/jquery.tablesorter.bootstrap.js"></script>
<script src="/JsLibraries/jquery.tablesorter.pager.js"></script>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
},
setActive: function (element) {
//Todo: Set active on first load
this.$('a').removeClass('active');
$(element).addClass('active');
},

View File

@ -0,0 +1,8 @@
'use strict';
define(['app'], function (app) {
NzbDrone.Series.Index.EmptySeriesCollectionView = Backbone.Marionette.CompositeView.extend({
template: 'Series/Index/EmptySeriesIndexTemplate'
});
});

View File

@ -0,0 +1,5 @@
<div class="row">
<div class="span12">
<div id="x-series-list"></div>
</div>
</div>

View File

@ -0,0 +1,17 @@
'use strict';
define(['app', 'Quality/QualityProfileCollection', 'Series/Index/List/ItemView', 'Config'], function (app, qualityProfileCollection) {
NzbDrone.Series.Index.List.CollectionView = Backbone.Marionette.CompositeView.extend({
itemView : NzbDrone.Series.Index.List.ItemView,
itemViewContainer : '#x-series-list',
template : 'Series/Index/List/CollectionTemplate',
qualityProfileCollection: qualityProfileCollection,
initialize: function () {
this.qualityProfileCollection.fetch();
this.itemViewOptions = { qualityProfiles: this.qualityProfileCollection };
}
});
});

View File

@ -9,19 +9,9 @@ define([
], function () {
NzbDrone.Series.Index.SeriesItemView = Backbone.Marionette.ItemView.extend({
NzbDrone.Series.Index.List.ItemView = Backbone.Marionette.ItemView.extend({
tagName : 'tr',
template: 'Series/Index/SeriesItemTemplate',
getTemplate: function(){
if (this.viewStyle === 1){
this.tagName = 'div';
return 'Series/Index/SeriesGridItemTemplate';
}
else {
return 'Series/Index/SeriesItemTemplate';
}
},
template: 'Series/Index/List/ItemTemplate',
ui: {
'progressbar': '.progress .bar'
@ -34,7 +24,6 @@ define([
initialize: function (options) {
this.qualityProfileCollection = options.qualityProfiles;
this.viewStyle = options.viewStyle;
},
editSeries: function () {

View File

@ -1,126 +0,0 @@
'use strict';
define(['app', 'Quality/QualityProfileCollection', 'Series/Index/SeriesItemView', 'Config'], function (app, qualityProfileCollection) {
NzbDrone.Series.Index.EmptySeriesCollectionView = Backbone.Marionette.CompositeView.extend({
template: 'Series/Index/EmptySeriesIndexTemplate',
tagName : 'tr'
});
NzbDrone.Series.Index.SeriesIndexCollectionView = Backbone.Marionette.CompositeView.extend({
itemView : NzbDrone.Series.Index.SeriesItemView,
itemViewContainer : '#x-series',
template : 'Series/Index/SeriesIndexTemplate',
qualityProfileCollection: qualityProfileCollection,
emptyView : NzbDrone.Series.Index.EmptySeriesCollectionView,
getTemplate: function(){
if (this.viewStyle === 1){
return 'Series/Index/SeriesIndexGridTemplate';
}
else {
return 'Series/Index/SeriesIndexTemplate';
}
},
ui: {
table: '.x-series-table'
},
events: {
'click .x-series-change-view': 'changeViewTemplate'
},
initialize: function () {
this.viewStyle = NzbDrone.Config.SeriesViewStyle();
this.collection = new NzbDrone.Series.SeriesCollection();
//Todo: This caused the onRendered event to be trigger twice, which displays two empty collection messages
//http://stackoverflow.com/questions/13065176/backbone-marionette-composit-view-onrender-executing-twice
this.collection.fetch();
this.qualityProfileCollection.fetch();
this.itemViewOptions = { qualityProfiles: this.qualityProfileCollection, viewStyle: this.viewStyle };
},
onItemRemoved: function () {
this.ui.table.trigger('update');
},
onCompositeCollectionRendered: function () {
this.ui.table.trigger('update');
if (!this.tableSorter && this.collection.length > 0) {
this.tableSorter = this.ui.table.tablesorter({
textExtraction: function (node) {
return node.innerHTML;
},
sortList : [
[1, 0]
],
headers : {
0: {
sorter: 'title'
},
1: {
sorter: 'innerHtml'
},
5: {
sorter: 'date'
},
6: {
sorter: false
},
7: {
sorter: false
}
}
});
this.applySortIcons();
this.ui.table.bind("sortEnd", function () {
this.applySortIcons();
});
}
else {
this.ui.table.trigger('update');
}
},
//Todo: Remove this from each view that requires it
applySortIcons : function () {
$(this.ui.table).find('th.tablesorter-header .tablesorter-header-inner i').each(function () {
$(this).remove();
});
$(this.ui.table).find('th.tablesorter-header').each(function () {
if ($(this).hasClass('tablesorter-headerDesc')) {
$(this).children('.tablesorter-header-inner').append('<i class="icon-sort-up pull-right">');
}
else if ($(this).hasClass('tablesorter-headerAsc')) {
$(this).children('.tablesorter-header-inner').append('<i class="icon-sort-down pull-right">');
}
else if (!$(this).hasClass('sorter-false')) {
$(this).children('.tablesorter-header-inner').append('<i class="icon-sort pull-right">');
}
});
},
changeViewTemplate: function(event) {
event.preventDefault();
if ($(event.currentTarget).hasClass('x-series-show-grid')) {
NzbDrone.Config.SeriesViewStyle(1);
}
else {
NzbDrone.Config.SeriesViewStyle(0);
}
this.viewStyle = NzbDrone.Config.SeriesViewStyle();
this.itemViewOptions.viewStyle = this.viewStyle;
this.render();
}
});
});

View File

@ -0,0 +1,142 @@
"use strict";
define([
'app',
'Series/Index/List/CollectionView',
'Config'
],
function (app) {
NzbDrone.Series.Index.SeriesIndexLayout = Backbone.Marionette.Layout.extend({
template: 'Series/Index/SeriesIndexLayoutTemplate',
regions: {
series: '#x-series'
},
ui: {
},
events: {
'click .x-series-change-view': 'changeView'
},
showTable: function () {
var columns =
[
{
name: 'status',
label: '',
editable: false,
cell: 'seriesStatus'
},
{
name: 'title',
label: 'Title',
editable: false,
cell: 'string'
},
{
name: 'seasonCount',
label: 'Seasons',
editable: false,
cell: 'integer'
},
{
name: 'quality',
label: 'Quality',
editable: false,
cell: 'integer'
},
{
name: 'network',
label: 'Network',
editable: false,
cell: 'string'
},
{
name: 'nextAiring',
label: 'Next Airing',
editable: false,
cell: 'datetime',
formatter: new Backgrid.AirDateFormatter()
},
{
name: 'episodes',
label: 'Episodes',
editable: false,
sortable: false,
cell: 'string'
},
{
name: 'edit',
label: '',
editable: false,
sortable: false,
cell: 'string'
}
];
this.series.show(new Backgrid.Grid(
{
columns : columns,
collection : this.seriesCollection,
className: 'table table-hover'
}));
},
showList: function () {
this.series.show(new NzbDrone.Series.Index.List.CollectionView({ collection: this.seriesCollection }));
},
initialize: function () {
this.viewStyle = NzbDrone.Config.SeriesViewStyle();
this.seriesCollection = new NzbDrone.Series.SeriesCollection();
this.seriesCollection.fetch();
},
onRender: function () {
var element = this.$('a[data-target="' + this.viewStyle + '"]').removeClass('active');
this.setActive(element);
},
onShow: function () {
switch (this.viewStyle) {
case 1:
this.showList();
break;
default:
this.showTable();
}
},
changeView: function (e) {
e.preventDefault();
var view = parseInt($(e.target).data('target'));
if (isNaN(view)) {
view = parseInt($(e.target).parent('a').data('target'));
this.setActive($(e.target).parent('a'));
}
else{
this.setActive($(e.target));
}
if (view === 1) {
NzbDrone.Config.SeriesViewStyle(1);
this.showList();
}
else {
NzbDrone.Config.SeriesViewStyle(0);
this.showTable();
}
},
setActive: function (element) {
this.$('a').removeClass('active');
$(element).addClass('active');
}
});
});

View File

@ -4,8 +4,8 @@
<div class="pull-right">
<div class="btn-toolbar">
<div class="btn-group">
<a class="btn x-series-change-view x-series-show-table" href="#" title="table"><i class="icon-table"></i></a>
<a class="btn x-series-change-view x-series-show-grid active" href="#" title="grid"><i class="icon-list"></i></a>
<a class="btn x-series-change-view x-series-show-table" href="#" title="Table" data-target="0"><i class="icon-table"></i></a>
<a class="btn x-series-change-view x-series-show-list" href="#" title="List" data-target="1"><i class="icon-list"></i></a>
</div>
</div>
</div>

View File

@ -1,28 +0,0 @@
<div class="row">
<div class="span10"></div>
<div class="span2">
<div class="pull-right">
<div class="btn-toolbar">
<div class="btn-group">
<a class="btn x-series-change-view x-series-show-table active" href="#" title="table"><i class="icon-table"></i></a>
<a class="btn x-series-change-view x-series-show-grid" href="#" title="grid"><i class="icon-list"></i></a>
</div>
</div>
</div>
</div>
</div>
<table class="table table-hover x-series-table">
<thead>
<tr>
<th title="Status"></th>
<th>Title</th>
<th>Seasons</th>
<th>Quality</th>
<th>Network</th>
<th>Next Airing</th>
<th>Episodes</th>
<th></th>
</tr>
</thead>
<tbody id="x-series"></tbody>
</table>

View File

@ -1,18 +0,0 @@
<td>{{{formatStatus status monitored}}}</td>
<td><a href="/series/details/{{id}}">{{title}}</a></td>
<td name="seasonCount"></td>
<td name="qualityProfileName"></td>
<td name="network"></td>
<!-- If only DT could access the backbone model -->
<td><span title="{{formatedDateString}}" data-date="{{nextAiring}}">{{bestDateString}}</span></td>
<td>
<div class="progress">
<span class="progressbar-back-text">{{episodeFileCount}} / {{episodeCount}}</span>
<div class="bar" style="width:{{percentOfEpisodes}}%"><span class="progressbar-front-text">{{episodeFileCount}} / {{episodeCount}}</span></div>
</div>
</td>
<td>
<i class="icon-cog x-edit" title="Edit Series"></i>
<i class="icon-remove x-remove" title="Delete Series"></i>
</td>

View File

@ -23,7 +23,6 @@ require.config({
handlebars: {
exports: 'Handlebars'
}
}
});
@ -33,6 +32,7 @@ define('app', function () {
window.NzbDrone.Config = {};
window.NzbDrone.Series = {};
window.NzbDrone.Series.Index = {};
window.NzbDrone.Series.Index.List = {};
window.NzbDrone.Series.Edit = {};
window.NzbDrone.Series.Delete = {};
window.NzbDrone.Series.Details = {};
@ -71,16 +71,48 @@ define('app', function () {
console.log('starting application');
//TODO: move this out of here
Handlebars.registerHelper("formatStatus", function (status, monitored) {
if (!monitored) {
return '<i class="icon-pause grid-icon" title="Not Monitored"></i>';
}
if (status === 0) {
return '<i class="icon-play grid-icon" title="Continuing"></i>';
}
//TODO: move these out of here
Backgrid.SeriesStatusCell = Backgrid.Cell.extend({
className: "series-status-cell",
return '<i class="icon-stop grid-icon" title="Ended"></i>';
render: function () {
this.$el.empty();
var monitored = this.model.get('monitored');
var status = this.model.get('status');
if (!monitored) {
this.$el.html('<i class="icon-pause grid-icon" title="Not Monitored"></i>');
}
else if (status === 0) {
this.$el.html('<i class="icon-play grid-icon" title="Continuing"></i>');
}
else {
this.$el.html('<i class="icon-stop grid-icon" title="Ended"></i>');
}
return this;
}
});
var AirDateFormatter = Backgrid.AirDateFormatter = function () {};
AirDateFormatter.prototype = new Backgrid.CellFormatter();
_.extend(AirDateFormatter.prototype, {
/**
Converts any value to a string using Ecmascript's implicit type
conversion. If the given value is `null` or `undefined`, an empty string is
returned instead.
@member Backgrid.StringFormatter
@param {*} rawValue
@return {string}
*/
fromRaw: function (rawValue) {
return 'Hello World';
if (_.isUndefined(rawValue) || _.isNull(rawValue)) return '';
return rawValue + '';
}
});
});