mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-24 22:35:39 -04:00
Moved source code under src folder - massive change
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
define(['app', 'handlebars'], function (App,Handlebars) {
|
||||
Handlebars.registerHelper('allowedLabeler', function () {
|
||||
var ret = '';
|
||||
var cutoff = this.cutoff;
|
||||
_.each(this.allowed, function (allowed) {
|
||||
if (allowed.id === cutoff.id) {
|
||||
ret += '<span class="label label-info" title="Cutoff">' + allowed.name + '</span> ';
|
||||
}
|
||||
|
||||
else {
|
||||
ret += '<span class="label">' + allowed.name + '</span> ';
|
||||
}
|
||||
});
|
||||
|
||||
return new Handlebars.SafeString(ret);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Delete: {{name}}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to delete '{{name}}'?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal">cancel</button>
|
||||
<button class="btn btn-danger x-confirm-delete">delete</button>
|
||||
</div>
|
||||
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
define(
|
||||
[
|
||||
'app',
|
||||
'marionette'
|
||||
], function (App, Marionette) {
|
||||
|
||||
return Marionette.ItemView.extend({
|
||||
template: 'Settings/Quality/Profile/DeleteTemplate',
|
||||
|
||||
events: {
|
||||
'click .x-confirm-delete': '_removeProfile'
|
||||
},
|
||||
|
||||
_removeProfile: function () {
|
||||
|
||||
this.model.destroy({
|
||||
wait: true
|
||||
}).done(function () {
|
||||
App.vent.trigger(App.Commands.CloseModalCommand);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
{{#if id}}
|
||||
<h3>Edit</h3>
|
||||
{{else}}
|
||||
<h3>Add</h3>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label">Name</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">Cutoff</label>
|
||||
<div class="controls">
|
||||
<select class="x-cutoff" name="cutoff.id" validation-name="cutoff">
|
||||
{{#each allowed}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<span class="help-inline">
|
||||
<i class="icon-question-sign" title="Once this quality is reached NzbDrone will no longer download episodes"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="offset1 span3">
|
||||
<h3>Available</h3>
|
||||
<select multiple="multiple" class="x-available-list">
|
||||
{{#each available}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<h3>Allowed</h3>
|
||||
<select multiple="multiple" class="x-allowed-list" validation-name="allowed">
|
||||
{{#each allowed}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{{#if id}}
|
||||
<button class="btn btn-danger pull-left x-delete">delete</button>
|
||||
{{/if}}
|
||||
<button class="btn" data-dismiss="modal">cancel</button>
|
||||
<button class="btn btn-primary x-save">save</button>
|
||||
</div>
|
||||
@@ -0,0 +1,81 @@
|
||||
'use strict';
|
||||
define(
|
||||
[
|
||||
'app',
|
||||
'marionette',
|
||||
'Mixins/AsModelBoundView',
|
||||
'Mixins/AsValidatedView'
|
||||
], function (App, Marionette, AsModelBoundView, AsValidatedView) {
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template: 'Settings/Quality/Profile/EditQualityProfileTemplate',
|
||||
|
||||
ui: {
|
||||
cutoff: '.x-cutoff'
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .x-save' : '_saveQualityProfile',
|
||||
'dblclick .x-available-list': '_moveQuality',
|
||||
'dblclick .x-allowed-list' : '_moveQuality'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.profileCollection = options.profileCollection;
|
||||
},
|
||||
|
||||
_moveQuality: function (event) {
|
||||
|
||||
var quality;
|
||||
var qualityId = event.target.value;
|
||||
var availableCollection = new Backbone.Collection(this.model.get('available'));
|
||||
availableCollection.comparator = function (model) {
|
||||
return model.get('weight');
|
||||
};
|
||||
|
||||
var allowedCollection = new Backbone.Collection(this.model.get('allowed'));
|
||||
allowedCollection.comparator = function (model) {
|
||||
return model.get('weight');
|
||||
};
|
||||
|
||||
if (availableCollection.get(qualityId)) {
|
||||
quality = availableCollection.get(qualityId);
|
||||
availableCollection.remove(quality);
|
||||
allowedCollection.add(quality);
|
||||
}
|
||||
else if (allowedCollection.get(qualityId)) {
|
||||
quality = allowedCollection.get(qualityId);
|
||||
|
||||
allowedCollection.remove(quality);
|
||||
availableCollection.add(quality);
|
||||
}
|
||||
else {
|
||||
throw 'couldnt find quality id ' + qualityId;
|
||||
}
|
||||
|
||||
this.model.set('available', availableCollection.toJSON());
|
||||
this.model.set('allowed', allowedCollection.toJSON());
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
_saveQualityProfile: function () {
|
||||
var self = this;
|
||||
var cutoff = _.findWhere(this.model.get('allowed'), { id: parseInt(this.ui.cutoff.val())});
|
||||
this.model.set('cutoff', cutoff);
|
||||
|
||||
var promise = this.model.save();
|
||||
|
||||
if (promise) {
|
||||
promise.done(function () {
|
||||
self.profileCollection.add(self.model, { merge: true });
|
||||
App.vent.trigger(App.Commands.CloseModalCommand);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AsValidatedView.call(view);
|
||||
return AsModelBoundView.call(view);
|
||||
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<fieldset>
|
||||
<legend>Quality Profiles</legend>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<ul class="quality-profiles">
|
||||
<li>
|
||||
<div class="quality-profile-item add-card x-add-card">
|
||||
<span class="center well">
|
||||
<i class="icon-plus" title="Add Profile"/>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
define(['app',
|
||||
'marionette',
|
||||
'Settings/Quality/Profile/QualityProfileView',
|
||||
'Settings/Quality/Profile/EditQualityProfileView',
|
||||
'Settings/Quality/Profile/QualityProfileSchemaCollection'
|
||||
], function (App, Marionette, QualityProfileView, EditProfileView, ProfileCollection) {
|
||||
|
||||
return Marionette.CompositeView.extend({
|
||||
itemView : QualityProfileView,
|
||||
itemViewContainer: '.quality-profiles',
|
||||
template : 'Settings/Quality/Profile/QualityProfileCollectionTemplate',
|
||||
|
||||
ui: {
|
||||
'addCard': '.x-add-card'
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .x-add-card': '_addProfile'
|
||||
},
|
||||
|
||||
appendHtml: function(collectionView, itemView, index){
|
||||
collectionView.ui.addCard.parent('li').before(itemView.el);
|
||||
},
|
||||
|
||||
_addProfile: function () {
|
||||
var self = this;
|
||||
var schemaCollection = new ProfileCollection();
|
||||
schemaCollection.fetch({
|
||||
success: function (collection) {
|
||||
var model = _.first(collection.models);
|
||||
model.set('id', undefined);
|
||||
model.set('name', '');
|
||||
model.collection = self.collection;
|
||||
|
||||
var view = new EditProfileView({ model: model, profileCollection: self.collection});
|
||||
App.modalRegion.show(view);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
define(
|
||||
[
|
||||
'backbone',
|
||||
'Quality/QualityProfileModel'
|
||||
], function (Backbone, QualityProfileModel) {
|
||||
|
||||
return Backbone.Collection.extend({
|
||||
model: QualityProfileModel,
|
||||
url : window.NzbDrone.ApiRoot + '/qualityprofiles/schema'
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="quality-profile-item">
|
||||
<div>
|
||||
<h3 name="name"></h3>
|
||||
<span class="btn-group pull-right">
|
||||
<button class="btn btn-mini btn-icon-only x-edit"><i class="icon-nd-edit"/></button>
|
||||
<button class="btn btn-mini btn-icon-only x-delete"><i class="icon-nd-delete"/></button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{allowedLabeler}}
|
||||
</div>
|
||||
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
define(
|
||||
[
|
||||
'app',
|
||||
'marionette',
|
||||
'Settings/Quality/Profile/EditQualityProfileView',
|
||||
'Settings/Quality/Profile/DeleteView',
|
||||
'Series/SeriesCollection',
|
||||
'Mixins/AsModelBoundView',
|
||||
'Settings/Quality/Profile/AllowedLabeler',
|
||||
'bootstrap',
|
||||
|
||||
], function (App, Marionette, EditProfileView, DeleteProfileView, SeriesCollection, AsModelBoundView) {
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template: 'Settings/Quality/Profile/QualityProfileTemplate',
|
||||
tagName : 'li',
|
||||
|
||||
ui: {
|
||||
'progressbar' : '.progress .bar',
|
||||
'deleteButton': '.x-delete'
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .x-edit' : '_editProfile',
|
||||
'click .x-delete': '_deleteProfile'
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
this.listenTo(this.model, 'sync', this.render);
|
||||
this.listenTo(SeriesCollection, 'all', this._updateDisableStatus)
|
||||
},
|
||||
|
||||
_editProfile: function () {
|
||||
var view = new EditProfileView({ model: this.model, profileCollection: this.model.collection });
|
||||
App.modalRegion.show(view);
|
||||
},
|
||||
|
||||
_deleteProfile: function () {
|
||||
if (this._isQualityInUse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var view = new DeleteProfileView({ model: this.model });
|
||||
App.modalRegion.show(view);
|
||||
},
|
||||
|
||||
onRender: function () {
|
||||
this._updateDisableStatus();
|
||||
},
|
||||
|
||||
_updateDisableStatus: function () {
|
||||
if (this._isQualityInUse()) {
|
||||
this.ui.deleteButton.addClass('disabled');
|
||||
this.ui.deleteButton.attr('title', 'Can\'t delete quality profiles attached to a series.');
|
||||
}
|
||||
else {
|
||||
this.ui.deleteButton.removeClass('disabled');
|
||||
this.ui.deleteButton.attr('title', 'Delete Quality Profile');
|
||||
}
|
||||
},
|
||||
|
||||
_isQualityInUse: function () {
|
||||
return SeriesCollection.where({'qualityProfileId': this.model.id}).length !== 0;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return AsModelBoundView.call(view);
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
"use strict";
|
||||
|
||||
define(
|
||||
[
|
||||
'marionette',
|
||||
'Quality/QualityProfileCollection',
|
||||
'Settings/Quality/Profile/QualityProfileCollectionView',
|
||||
'Quality/QualitySizeCollection',
|
||||
'Settings/Quality/Size/QualitySizeCollectionView'
|
||||
], function (Marionette, QualityProfileCollection, QualityProfileCollectionView, QualitySizeCollection, QualitySizeCollectionView) {
|
||||
return Marionette.Layout.extend({
|
||||
template: 'Settings/Quality/QualityLayoutTemplate',
|
||||
|
||||
regions: {
|
||||
qualityProfile : '#quality-profile',
|
||||
qualitySize : '#quality-size'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.settings = options.settings;
|
||||
QualityProfileCollection.fetch();
|
||||
this.qualitySizeCollection = new QualitySizeCollection();
|
||||
this.qualitySizeCollection.fetch();
|
||||
},
|
||||
|
||||
onShow: function () {
|
||||
this.qualityProfile.show(new QualityProfileCollectionView({collection: QualityProfileCollection}));
|
||||
this.qualitySize.show(new QualitySizeCollectionView({collection: this.qualitySizeCollection}));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="row">
|
||||
<div class="span12" id="quality-profile"/>
|
||||
</div>
|
||||
<!--<div class="row">
|
||||
<div class="span12" id="quality-size"/>
|
||||
</div>-->
|
||||
@@ -0,0 +1,4 @@
|
||||
<fieldset>
|
||||
<legend>Quality Size Limits</legend>
|
||||
<ul class="quality-sizes"/>
|
||||
</fieldset>
|
||||
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
define(['marionette', 'Settings/Quality/Size/QualitySizeView'], function (Marionette, QualitySizeView) {
|
||||
return Marionette.CompositeView.extend({
|
||||
itemView : QualitySizeView,
|
||||
itemViewContainer: '.quality-sizes',
|
||||
template : 'Settings/Quality/Size/QualitySizeCollectionTemplate'
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
<div class="quality-size-item">
|
||||
<h2 class="center-block">{{name}}</h2>
|
||||
<div class="size">
|
||||
<div class="size-value-wrapper">
|
||||
<div>
|
||||
<span class="label label-large label-warning x-size-thirty"
|
||||
name="thirtyMinuteSize"
|
||||
title="Maximum size for a 30 minute episode">
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label label-large label-info x-size-sixty"
|
||||
name="sixtyMinuteSize"
|
||||
title="Maximum size for a 60 minute episode">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" name="maxSize" class="knob x-knob" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
define(['marionette', 'Mixins/AsModelBoundView', 'filesize', 'jquery.knob' ], function (Marionette, AsModelBoundView, Filesize) {
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template : 'Settings/Quality/Size/QualitySizeTemplate',
|
||||
tagName : 'li',
|
||||
|
||||
ui: {
|
||||
knob : '.x-knob',
|
||||
thirtyMinuteSize: '.x-size-thirty',
|
||||
sixtyMinuteSize : '.x-size-sixty'
|
||||
},
|
||||
|
||||
events: {
|
||||
'change .x-knob': '_changeMaxSize'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.qualityProfileCollection = options.qualityProfiles;
|
||||
this.filesize = Filesize;
|
||||
},
|
||||
|
||||
onRender: function () {
|
||||
this.ui.knob.knob({
|
||||
min : 0,
|
||||
max : 200,
|
||||
step : 1,
|
||||
cursor : 25,
|
||||
width : 150,
|
||||
stopper : true,
|
||||
displayInput : false
|
||||
});
|
||||
|
||||
this._changeMaxSize();
|
||||
},
|
||||
|
||||
_changeMaxSize: function () {
|
||||
var maxSize = this.model.get('maxSize');
|
||||
var bytes = maxSize * 1024 * 1024;
|
||||
var thirty = Filesize(bytes * 30, 1, false);
|
||||
var sixty = Filesize(bytes * 60, 1, false);
|
||||
|
||||
if (parseInt(maxSize) === 0) {
|
||||
thirty = 'No Limit';
|
||||
sixty = 'No Limit';
|
||||
}
|
||||
|
||||
this.ui.thirtyMinuteSize.html(thirty);
|
||||
this.ui.sixtyMinuteSize.html(sixty);
|
||||
}
|
||||
});
|
||||
|
||||
return AsModelBoundView.call(view);
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
@import "../../Shared/Styles/card";
|
||||
|
||||
.quality-profiles, .quality-sizes {
|
||||
li {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.quality-profile-item {
|
||||
|
||||
.card;
|
||||
|
||||
width: 300px;
|
||||
height: 120px;
|
||||
padding: 10px 15px;
|
||||
|
||||
h3 {
|
||||
margin-top: 0px;
|
||||
display: inline-block;
|
||||
width: 240px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
&.add-card {
|
||||
.center {
|
||||
margin-top: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.quality-size-item {
|
||||
|
||||
.card;
|
||||
text-align: center;
|
||||
|
||||
width: 200px;
|
||||
height: 220px;
|
||||
padding: 10px 15px;
|
||||
|
||||
h3 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.size {
|
||||
position: relative;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.knob {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.size-value-wrapper {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
width: 100%;
|
||||
|
||||
div {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#quality-size {
|
||||
overflow: hidden;
|
||||
}
|
||||
Reference in New Issue
Block a user