removed backbone from VS solution,

renamed NzbDrone.Backbone to UI
This commit is contained in:
kay.one 2013-03-29 12:18:44 -07:00
commit 663160c06a
230 changed files with 57 additions and 386 deletions

View file

@ -0,0 +1,17 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Delete: {{title}}</h3>
</div>
<div class="modal-body">
<p>Are you sure you want to delete '{{title}}'?</p>
<div class="series-delete-files">
<label class="checkbox">
<input class="x-delete-files" type="checkbox" value="true">
Delete all files from disk?
</label>
</div>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal">cancel</button>
<button class="btn btn-danger x-confirm-delete">delete</button>
</div>

View file

@ -0,0 +1,37 @@
'use strict';
define(['app', 'Series/SeriesModel'], function () {
NzbDrone.Series.Delete.DeleteSeriesView = Backbone.Marionette.ItemView.extend({
template:'Series/Delete/DeleteSeriesTemplate',
tagName:'div',
className:"modal",
events:{
'click .x-confirm-delete':'removeSeries'
},
ui:{
deleteFiles:'.x-delete-files'
},
onRender:function () {
NzbDrone.ModelBinder.bind(this.model, this.el);
},
removeSeries:function () {
var deleteFiles = this.ui.deleteFiles.prop('checked');
this.model.destroy({
data:{ 'deleteFiles':deleteFiles },
success:function (model) {
model.collection.remove(model);
}
});
NzbDrone.modalRegion.close();
}
});
});

View file

@ -0,0 +1 @@
{{title}}

View file

@ -0,0 +1,19 @@
'use strict';
define(['app', 'Series/SeasonModel'], function () {
NzbDrone.Series.Details.EpisodeItemView = Backbone.Marionette.ItemView.extend({
template: 'Series/Details/EpisodeItemTemplate',
tagName: 'tr',
ui: {
},
events: {
},
onRender: function () {
NzbDrone.ModelBinder.bind(this.model, this.el);
}
});
});

View file

@ -0,0 +1,15 @@
<h3>{{seasonTitle}}</h3>
<table class="table table-hover x-season-table">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Air Date</th>
<th>Quality</th>
<th>Controls</th>
</tr>
</thead>
<tbody class="x-episodes">
</tbody>
</table>

View file

@ -0,0 +1,16 @@
'use strict';
define(['app', 'Series/Details/EpisodeItemView'], function () {
NzbDrone.Series.Details.SeasonCompositeView = Backbone.Marionette.CompositeView.extend({
itemView: NzbDrone.Series.Details.EpisodeItemView,
itemViewContainer: '.x-episodes',
template: 'Series/Details/SeasonCompositeTemplate',
initialize: function() {
this.collection =new NzbDrone.Series.EpisodeCollection();
this.collection.fetch({data: {
seriesId: this.model.get('seriesId'),
seasonNumber:this.model.get('seasonNumber')
}});
}
});
});

View file

@ -0,0 +1,6 @@
<div>
<div class="x-series-details">
{{overview}}
</div>
<div class="x-series-seasons"></div>
</div>

View file

@ -0,0 +1,13 @@
define(['app', 'Quality/QualityProfileCollection', 'Series/Details/SeasonCompositeView', 'Series/SeasonCollection'], function () {
NzbDrone.Series.Details.SeriesDetailsView = Backbone.Marionette.CompositeView.extend({
itemView: NzbDrone.Series.Details.SeasonCompositeView,
itemViewContainer: '.x-series-seasons',
template: 'Series/Details/SeriesDetailsTemplate',
initialize: function () {
this.collection = new NzbDrone.Series.SeasonCollection();
this.collection.fetch({data: { seriesId: this.model.get('id') }});
}
});
});

View file

@ -0,0 +1,86 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Edit: {{title}}</h3>
</div>
<div class="modal-body">
<div class="form-horizontal">
<div class="control-group">
<label class="control-label">Monitored</label>
<div class="controls">
<div class="switch">
<input type="checkbox" name="monitored" />
</div>
<span class="help-inline-checkbox">
<i class="icon-question-sign" title="Should NzbDrone download episodes for this series?"></i>
</span>
</div>
</div>
<div class="control-group">
<label class="control-label">Use Season Folder</label>
<div class="controls">
<div class="switch">
<input type="checkbox" name="seasonFolder" />
</div>
<span class="help-inline-checkbox">
<i class="icon-question-sign" title="Should downloaded episodes be stored in season folders?"></i>
</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputQualityProfile">Quality Profile</label>
<div class="controls">
<select class="x-quality-profile" id="inputQualityProfile" name="qualityProfileId">
{{#each qualityProfiles.models}}
<option value="{{id}}">{{attributes.name}}</option>
{{/each}}
</select>
<span class="help-inline">
<i class="icon-question-sign" title="Which Quality Profile should NzbDrone use to download episodes?"></i>
</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputPath">Path</label>
<div class="controls">
<input type="text" id="inputPath" placeholder="Path" name="path">
<span class="help-inline">
<i class="icon-question-sign" title="Where should NzbDrone store episodes for this series?"></i>
</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputBacklogSetting">Backlog Setting</label>
<div class="controls">
<select id="inputBacklogSetting" class="inputClass x-backlog-setting" name="backlogSetting">
<option value="0">Inherit</option>
<option value="1">Enable</option>
<option value="2">Disable</option>
</select>
<span class="help-inline">
<i class="icon-question-sign" title="Should NzbDrone search for missing episodes every 30 days?"></i>
</span>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputCustomStartDate">Custom Start Date</label>
<div class="controls">
<input type="date" id="inputCustomStartDate" name="customStartDate">
<span class="help-inline">
<i class="icon-question-sign" title="Should NzbDrone only download episodes after your preferred start date?"></i>
</span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-danger pull-left x-remove" >delete</button>
<button class="btn" data-dismiss="modal">cancel</button>
<button class="btn btn-primary x-save">save</button>
</div>

View file

@ -0,0 +1,46 @@
'use strict';
define(['app', 'Series/SeriesModel', 'Series/Delete/DeleteSeriesView', 'Quality/QualityProfileCollection'], function () {
NzbDrone.Series.Edit.EditSeriesView = Backbone.Marionette.ItemView.extend({
template: 'Series/Edit/EditSeriesTemplate',
tagName: 'div',
className: "modal",
ui: {
progressbar: '.progress .bar',
qualityProfile: '.x-quality-profile',
backlogSettings: '.x-backlog-setting',
switch: '.switch'
},
events: {
'click .x-save': 'saveSeries',
'click .x-remove': 'removeSeries'
},
onRender: function () {
NzbDrone.ModelBinder.bind(this.model, this.el);
this.ui.switch.bootstrapSwitch();
},
saveSeries: function () {
//Todo: Get qualityProfile + backlog setting from UI
var qualityProfile = this.ui.qualityProfile.val();
var qualityProfileText = this.ui.qualityProfile.children('option:selected').text();
var backlogSetting = this.ui.backlogSettings.val();
this.model.set({ qualityProfileId: qualityProfile, backlogSetting: backlogSetting, qualityProfileName: qualityProfileText });
this.model.save();
this.trigger('saved');
this.$el.parent().modal('hide');
},
removeSeries: function () {
var view = new NzbDrone.Series.Delete.DeleteSeriesView({ model: this.model });
NzbDrone.modalRegion.show(view);
}
});
});

View file

@ -0,0 +1,6 @@
define(['app', 'Series/EpisodeModel'], function () {
NzbDrone.Series.EpisodeCollection = Backbone.Collection.extend({
url: NzbDrone.Constants.ApiRoot + '/episodes',
model: NzbDrone.Series.EpisodeModel
});
});

12
UI/Series/EpisodeModel.js Normal file
View file

@ -0,0 +1,12 @@
define(['app'], function () {
NzbDrone.Series.EpisodeModel = Backbone.Model.extend({
mutators: {
},
defaults: {
seasonNumber: 0
}
});
});

View file

@ -0,0 +1 @@
<td colspan="8">No series found</td>

View file

@ -0,0 +1,94 @@
'use strict';
define(['app', 'Quality/QualityProfileCollection', 'Series/Index/SeriesItemView'], function (app, qualityProfileCollection) {
NzbDrone.Series.Index.SeriesIndexCollectionView = Backbone.Marionette.CompositeView.extend({
itemView: NzbDrone.Series.Index.SeriesItemView,
itemViewContainer: 'tbody',
template: 'Series/Index/SeriesIndexTemplate',
qualityProfileCollection: qualityProfileCollection,
//emptyView: NzbDrone.Series.EmptySeriesCollectionView,
initialize: function () {
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 };
},
ui:{
table : '.x-series-table'
},
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">');
});
}
});
});
NzbDrone.Series.Index.EmptySeriesCollectionView = Backbone.Marionette.CompositeView.extend({
template: 'Series/Index/EmptySeriesCollectionTemplate',
tagName: 'tr'
});

View file

@ -0,0 +1,15 @@
<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></tbody>
</table>

View file

@ -0,0 +1,17 @@
<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

@ -0,0 +1,48 @@
'use strict';
define([
'app',
'Quality/QualityProfileCollection',
'Series/SeriesCollection',
'Series/Edit/EditSeriesView',
'Series/Delete/DeleteSeriesView'
], function () {
NzbDrone.Series.Index.SeriesItemView = Backbone.Marionette.ItemView.extend({
template: 'Series/Index/SeriesItemTemplate',
tagName: 'tr',
ui: {
'progressbar': '.progress .bar'
},
events: {
'click .x-edit': 'editSeries',
'click .x-remove': 'removeSeries'
},
initialize: function (options) {
this.qualityProfileCollection = options.qualityProfiles;
},
onRender: function () {
NzbDrone.ModelBinder.bind(this.model, this.el);
},
editSeries: function () {
var view = new NzbDrone.Series.Edit.EditSeriesView({ model: this.model});
NzbDrone.vent.trigger(NzbDrone.Events.OpenModalDialog, {
view: view
});
},
removeSeries: function () {
var view = new NzbDrone.Series.Delete.DeleteSeriesView({ model: this.model });
NzbDrone.vent.trigger(NzbDrone.Events.OpenModalDialog, {
view: view
});
}
});
});

View file

@ -0,0 +1,6 @@
define(['app','Series/SeasonModel'], function () {
NzbDrone.Series.SeasonCollection = Backbone.Collection.extend({
url: NzbDrone.Constants.ApiRoot + '/season',
model: NzbDrone.Series.SeasonModel
});
});

21
UI/Series/SeasonModel.js Normal file
View file

@ -0,0 +1,21 @@
define(['app'], function () {
NzbDrone.Series.SeasonModel = Backbone.Model.extend({
mutators: {
seasonTitle: function () {
var seasonNumber = this.get('seasonNumber');
if (seasonNumber === 0) {
return "Specials"
}
return "Season " + seasonNumber;
}
},
defaults: {
seasonNumber: 0
}
});
});

View file

@ -0,0 +1,6 @@
define(['app', 'Series/SeriesModel'], function () {
NzbDrone.Series.SeriesCollection = Backbone.Collection.extend({
url: NzbDrone.Constants.ApiRoot + '/series',
model: NzbDrone.Series.SeriesModel
});
});

31
UI/Series/SeriesModel.js Normal file
View file

@ -0,0 +1,31 @@
define(['app', 'Quality/QualityProfileCollection'], function (app, qualityProfileCollection) {
NzbDrone.Series.SeriesModel = Backbone.Model.extend({
urlRoot: NzbDrone.Constants.ApiRoot + '/series',
mutators: {
bestDateString: function () {
return bestDateString(this.get('nextAiring'));
},
percentOfEpisodes: function () {
var episodeCount = this.get('episodeCount');
var episodeFileCount = this.get('episodeFileCount');
var percent = 100;
if (episodeCount > 0)
percent = episodeFileCount / episodeCount * 100;
return percent;
}
},
defaults: {
episodeFileCount: 0,
episodeCount: 0,
qualityProfiles: qualityProfileCollection
}
});
});