From 6b8314206ab5d6b8693e3a28dfd252b8e84469a6 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Thu, 7 Mar 2013 00:01:18 -0800 Subject: [PATCH] Quality Settings divided up in layout Using bootstrap slider --- NzbDrone.Api/AutomapperBootstraper.cs | 4 +- NzbDrone.Api/NzbDrone.Api.csproj | 4 +- ...lityTypeModule.cs => QualitySizeModule.cs} | 14 +- ...ityTypeModel.cs => QualitySizeResource.cs} | 2 +- .../Content/bootstrap.slider.css | 138 ++++++++ NzbDrone.Backbone/Index.html | 2 + .../JsLibraries/bootstrap.slider.js | 335 ++++++++++++++++++ NzbDrone.Backbone/NzbDrone.Backbone.csproj | 8 +- .../Quality/QualitySizeCollection.js | 6 + NzbDrone.Backbone/Quality/QualitySizeModel.js | 17 + .../Quality/qualityTypeCollection.js | 4 - NzbDrone.Backbone/Quality/qualityTypeModel.js | 34 -- .../Series/Index/SeriesItemView.js | 1 - .../Settings/Naming/NamingView.js | 5 + .../Settings/Quality/QualityLayout.js | 41 +++ .../Quality/QualityLayoutTemplate.html | 9 + .../QualityProfileCollectionTemplate.html | 5 + .../Quality/QualityProfileCollectionView.js | 22 ++ .../Settings/Quality/QualityProfileView.js | 46 +++ .../QualitySizeCollectionTemplate.html | 4 + .../Quality/QualitySizeCollectionView.js | 22 ++ .../Settings/Quality/QualitySizeTemplate.html | 6 + .../Settings/Quality/QualitySizeView.js | 48 +++ .../Settings/Quality/QualityTemplate.html | 17 +- .../Settings/Quality/QualityView.js | 6 + NzbDrone.Backbone/Settings/SettingsLayout.js | 9 +- 26 files changed, 745 insertions(+), 64 deletions(-) rename NzbDrone.Api/QualityType/{QualityTypeModule.cs => QualitySizeModule.cs} (73%) rename NzbDrone.Api/QualityType/{QualityTypeModel.cs => QualitySizeResource.cs} (86%) create mode 100644 NzbDrone.Backbone/Content/bootstrap.slider.css create mode 100644 NzbDrone.Backbone/JsLibraries/bootstrap.slider.js create mode 100644 NzbDrone.Backbone/Quality/QualitySizeCollection.js create mode 100644 NzbDrone.Backbone/Quality/QualitySizeModel.js delete mode 100644 NzbDrone.Backbone/Quality/qualityTypeCollection.js delete mode 100644 NzbDrone.Backbone/Quality/qualityTypeModel.js create mode 100644 NzbDrone.Backbone/Settings/Quality/QualityLayout.js create mode 100644 NzbDrone.Backbone/Settings/Quality/QualityLayoutTemplate.html create mode 100644 NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionTemplate.html create mode 100644 NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionView.js create mode 100644 NzbDrone.Backbone/Settings/Quality/QualityProfileView.js create mode 100644 NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionTemplate.html create mode 100644 NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionView.js create mode 100644 NzbDrone.Backbone/Settings/Quality/QualitySizeTemplate.html create mode 100644 NzbDrone.Backbone/Settings/Quality/QualitySizeView.js diff --git a/NzbDrone.Api/AutomapperBootstraper.cs b/NzbDrone.Api/AutomapperBootstraper.cs index 74060e6aa..6eac1d014 100644 --- a/NzbDrone.Api/AutomapperBootstraper.cs +++ b/NzbDrone.Api/AutomapperBootstraper.cs @@ -29,10 +29,10 @@ namespace NzbDrone.Api .ForMember(dest => dest.Allowed, opt => opt.Ignore()); //QualitySize - Mapper.CreateMap() + Mapper.CreateMap() .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.QualityId)); - Mapper.CreateMap() + Mapper.CreateMap() .ForMember(dest => dest.QualityId, opt => opt.MapFrom(src => src.Id)); //Series diff --git a/NzbDrone.Api/NzbDrone.Api.csproj b/NzbDrone.Api/NzbDrone.Api.csproj index c1453cd26..8e68466f3 100644 --- a/NzbDrone.Api/NzbDrone.Api.csproj +++ b/NzbDrone.Api/NzbDrone.Api.csproj @@ -139,8 +139,8 @@ - - + + diff --git a/NzbDrone.Api/QualityType/QualityTypeModule.cs b/NzbDrone.Api/QualityType/QualitySizeModule.cs similarity index 73% rename from NzbDrone.Api/QualityType/QualityTypeModule.cs rename to NzbDrone.Api/QualityType/QualitySizeModule.cs index 4c9ba2889..f64df9688 100644 --- a/NzbDrone.Api/QualityType/QualityTypeModule.cs +++ b/NzbDrone.Api/QualityType/QualitySizeModule.cs @@ -9,12 +9,12 @@ using NzbDrone.Core.Qualities; namespace NzbDrone.Api.QualityType { - public class QualityTypeModule : NzbDroneApiModule + public class QualitySizeModule : NzbDroneApiModule { private readonly QualitySizeService _qualityTypeProvider; - public QualityTypeModule(QualitySizeService qualityTypeProvider) - : base("/QualityTypes") + public QualitySizeModule(QualitySizeService qualityTypeProvider) + : base("/qualitysizes") { _qualityTypeProvider = qualityTypeProvider; @@ -25,9 +25,9 @@ namespace NzbDrone.Api.QualityType private Response PutQualityType() { - var model = Request.Body.FromJson(); + var model = Request.Body.FromJson(); - var type = Mapper.Map(model); + var type = Mapper.Map(model); _qualityTypeProvider.Update(type); return model.AsResponse(); @@ -37,13 +37,13 @@ namespace NzbDrone.Api.QualityType private Response GetQualityType(int id) { var type = _qualityTypeProvider.Get(id); - return Mapper.Map(type).AsResponse(); + return Mapper.Map(type).AsResponse(); } private Response GetQualityType() { var types = _qualityTypeProvider.All().Where(qualityType => qualityType.QualityId != 0 && qualityType.QualityId != 10).ToList(); - var responseModel = Mapper.Map, List>(types); + var responseModel = Mapper.Map, List>(types); return responseModel.AsResponse(); } diff --git a/NzbDrone.Api/QualityType/QualityTypeModel.cs b/NzbDrone.Api/QualityType/QualitySizeResource.cs similarity index 86% rename from NzbDrone.Api/QualityType/QualityTypeModel.cs rename to NzbDrone.Api/QualityType/QualitySizeResource.cs index a503cf28a..08e1a6653 100644 --- a/NzbDrone.Api/QualityType/QualityTypeModel.cs +++ b/NzbDrone.Api/QualityType/QualitySizeResource.cs @@ -3,7 +3,7 @@ using System.Linq; namespace NzbDrone.Api.QualityType { - public class QualityTypeModel + public class QualitySizeResource { public Int32 Id { get; set; } public String Name { get; set; } diff --git a/NzbDrone.Backbone/Content/bootstrap.slider.css b/NzbDrone.Backbone/Content/bootstrap.slider.css new file mode 100644 index 000000000..b527aa868 --- /dev/null +++ b/NzbDrone.Backbone/Content/bootstrap.slider.css @@ -0,0 +1,138 @@ +/*! + * Slider for Bootstrap + * + * Copyright 2012 Stefan Petre + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.slider { + display: inline-block; + vertical-align: middle; + position: relative; +} +.slider.slider-horizontal { + width: 210px; + height: 20px; +} +.slider.slider-horizontal .slider-track { + height: 10px; + width: 100%; + margin-top: -5px; + top: 50%; + left: 0; +} +.slider.slider-horizontal .slider-selection { + height: 100%; + top: 0; + bottom: 0; +} +.slider.slider-horizontal .slider-handle { + margin-left: -10px; + margin-top: -5px; +} +.slider.slider-horizontal .slider-handle.triangle { + border-width: 0 10px 10px 10px; + width: 0; + height: 0; + border-bottom-color: #0480be; + margin-top: 0; +} +.slider.slider-vertical { + height: 210px; + width: 20px; +} +.slider.slider-vertical .slider-track { + width: 10px; + height: 100%; + margin-left: -5px; + left: 50%; + top: 0; +} +.slider.slider-vertical .slider-selection { + width: 100%; + left: 0; + top: 0; + bottom: 0; +} +.slider.slider-vertical .slider-handle { + margin-left: -5px; + margin-top: -10px; +} +.slider.slider-vertical .slider-handle.triangle { + border-width: 10px 0 10px 10px; + width: 1px; + height: 1px; + border-left-color: #0480be; + margin-left: 0; +} +.slider input { + display: none; +} +.slider .tooltip-inner { + white-space: nowrap; +} +.slider-track { + position: absolute; + cursor: pointer; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.slider-selection { + position: absolute; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5); + background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5); + background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.slider-handle { + position: absolute; + width: 20px; + height: 20px; + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); + opacity: 0.8; + border: 0px solid transparent; +} +.slider-handle.round { + -webkit-border-radius: 20px; + -moz-border-radius: 20px; + border-radius: 20px; +} +.slider-handle.triangle { + background: transparent none; +} \ No newline at end of file diff --git a/NzbDrone.Backbone/Index.html b/NzbDrone.Backbone/Index.html index 5737477ab..13a28fb7f 100644 --- a/NzbDrone.Backbone/Index.html +++ b/NzbDrone.Backbone/Index.html @@ -10,6 +10,7 @@ + @@ -99,6 +100,7 @@ + diff --git a/NzbDrone.Backbone/JsLibraries/bootstrap.slider.js b/NzbDrone.Backbone/JsLibraries/bootstrap.slider.js new file mode 100644 index 000000000..6940c5cb5 --- /dev/null +++ b/NzbDrone.Backbone/JsLibraries/bootstrap.slider.js @@ -0,0 +1,335 @@ +/* ========================================================= + * bootstrap-slider.js v2.0.0 + * http://www.eyecon.ro/bootstrap-slider + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +!function( $ ) { + + var Slider = function(element, options) { + this.element = $(element); + this.picker = $('
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
'+ + '
') + .insertBefore(this.element) + .append(this.element); + this.id = this.element.data('slider-id')||options.id; + if (this.id) { + this.picker[0].id = this.id; + } + + var tooltip = this.element.data('slider-tooltip')||options.tooltip; + + this.tooltip = this.picker.find('.tooltip'); + this.tooltipInner = this.tooltip.find('div.tooltip-inner'); + + this.orientation = this.element.data('slider-orientation')||options.orientation; + switch(this.orientation) { + case 'vertical': + this.picker.addClass('slider-vertical'); + this.stylePos = 'top'; + this.mousePos = 'pageY'; + this.sizePos = 'offsetHeight'; + this.tooltip.addClass('right')[0].style.left = '100%'; + break; + default: + this.picker + .addClass('slider-horizontal') + .css('width', this.element.outerWidth()); + this.orientation = 'horizontal'; + this.stylePos = 'left'; + this.mousePos = 'pageX'; + this.sizePos = 'offsetWidth'; + this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px'; + break; + } + + this.min = this.element.data('slider-min')||options.min; + this.max = this.element.data('slider-max')||options.max; + this.step = this.element.data('slider-step')||options.step; + this.value = this.element.data('slider-value')||options.value; + if (this.value[1]) { + this.range = true; + } + + this.selection = this.element.data('slider-selection')||options.selection; + this.selectionEl = this.picker.find('.slider-selection'); + if (this.selection === 'none') { + this.selectionEl.addClass('hide'); + } + this.selectionElStyle = this.selectionEl[0].style; + + + this.handle1 = this.picker.find('.slider-handle:first'); + this.handle1Stype = this.handle1[0].style; + this.handle2 = this.picker.find('.slider-handle:last'); + this.handle2Stype = this.handle2[0].style; + + var handle = this.element.data('slider-handle')||options.handle; + switch(handle) { + case 'round': + this.handle1.addClass('round'); + this.handle2.addClass('round'); + break + case 'triangle': + this.handle1.addClass('triangle'); + this.handle2.addClass('triangle'); + break + } + + if (this.range) { + this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); + this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); + } else { + this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; + this.handle2.addClass('hide'); + if (this.selection == 'after') { + this.value[1] = this.max; + } else { + this.value[1] = this.min; + } + } + this.diff = this.max - this.min; + this.percentage = [ + (this.value[0]-this.min)*100/this.diff, + (this.value[1]-this.min)*100/this.diff, + this.step*100/this.diff + ]; + + this.offset = this.picker.offset(); + this.size = this.picker[0][this.sizePos]; + + this.layout(); + this.picker.on({ + mousedown: $.proxy(this.mousedown, this)}); + if (tooltip === 'show') { + this.picker.on({ + mouseenter: $.proxy(this.showTooltip, this), + mouseleave: $.proxy(this.hideTooltip, this) + }); + } else { + this.tooltip.addClass('hide'); + } + }; + + Slider.prototype = { + constructor: Slider, + + over: false, + inDrag: false, + + showTooltip: function(){ + this.tooltip.addClass('in'); + //var left = Math.round(this.percent*this.width); + //this.tooltip.css('left', left - this.tooltip.outerWidth()/2); + this.over = true; + }, + + hideTooltip: function(){ + if (this.inDrag === false) { + this.tooltip.removeClass('in'); + } + this.over = false; + }, + + layout: function(){ + this.handle1Stype[this.stylePos] = this.percentage[0]+'%'; + this.handle2Stype[this.stylePos] = this.percentage[1]+'%'; + if (this.orientation == 'vertical') { + this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%'; + this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; + } else { + this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%'; + this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; + } + if (this.range) { + this.tooltipInner.text( + (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step) + + ' : ' + + (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step) + ); + this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; + } else { + this.tooltipInner.text( + (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step) + ); + this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; + } + }, + + mousedown: function(ev) { + this.offset = this.picker.offset(); + this.size = this.picker[0][this.sizePos]; + + var percentage = this.getPercentage(ev); + + if (this.range) { + var diff1 = Math.abs(this.percentage[0] - percentage); + var diff2 = Math.abs(this.percentage[1] - percentage); + this.dragged = (diff1 < diff2) ? 0 : 1; + } else { + this.dragged = 0; + } + + this.percentage[this.dragged] = percentage; + this.layout(); + + $(document).on({ + mousemove: $.proxy(this.mousemove, this), + mouseup: $.proxy(this.mouseup, this) + }); + this.inDrag = true; + var val = this.calculateValue(); + this.element.trigger({ + type: 'slideStart', + value: val + }).trigger({ + type: 'slide', + value: val + }); + return false; + }, + + mousemove: function(ev) { + var percentage = this.getPercentage(ev); + if (this.range) { + if (this.dragged === 0 && this.percentage[1] < percentage) { + this.percentage[0] = this.percentage[1]; + this.dragged = 1; + } else if (this.dragged === 1 && this.percentage[0] > percentage) { + this.percentage[1] = this.percentage[0]; + this.dragged = 0; + } + } + this.percentage[this.dragged] = percentage; + this.layout(); + var val = this.calculateValue(); + this.element + .trigger({ + type: 'slide', + value: val + }) + .data('value', val) + .prop('value', val); + return false; + }, + + mouseup: function(ev) { + $(document).off({ + mousemove: this.mousemove, + mouseup: this.mouseup + }); + this.inDrag = false; + if (this.over == false) { + this.hideTooltip(); + } + this.element; + var val = this.calculateValue(); + this.element + .trigger({ + type: 'slideStop', + value: val + }) + .data('value', val) + .prop('value', val); + return false; + }, + + calculateValue: function() { + var val; + if (this.range) { + val = [ + (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step), + (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step) + ]; + this.value = val; + } else { + val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step); + this.value = [val, this.value[1]]; + } + return val; + }, + + getPercentage: function(ev) { + var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size; + percentage = Math.round(percentage/this.percentage[2])*this.percentage[2]; + return Math.max(0, Math.min(100, percentage)); + }, + + getValue: function() { + if (this.range) { + return this.value; + } + return this.value[0]; + }, + + setValue: function(val) { + this.value = val; + + if (this.range) { + this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); + this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); + } else { + this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; + this.handle2.addClass('hide'); + if (this.selection == 'after') { + this.value[1] = this.max; + } else { + this.value[1] = this.min; + } + } + this.diff = this.max - this.min; + this.percentage = [ + (this.value[0]-this.min)*100/this.diff, + (this.value[1]-this.min)*100/this.diff, + this.step*100/this.diff + ]; + } + }; + + $.fn.slider = function ( option ) { + return this.each(function () { + var $this = $(this), + data = $this.data('slider'), + options = typeof option === 'object' && option; + if (!data) { + $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options)))); + } + if (typeof option == 'string') { + data[option](); + } + }) + }; + + $.fn.slider.defaults = { + min: 0, + max: 10, + step: 1, + orientation: 'horizontal', + value: 5, + selection: 'before', + tooltip: 'show', + handle: 'round' + }; + + $.fn.slider.Constructor = Slider; + +}( window.jQuery ); \ No newline at end of file diff --git a/NzbDrone.Backbone/NzbDrone.Backbone.csproj b/NzbDrone.Backbone/NzbDrone.Backbone.csproj index 10d427023..714bee6a3 100644 --- a/NzbDrone.Backbone/NzbDrone.Backbone.csproj +++ b/NzbDrone.Backbone/NzbDrone.Backbone.csproj @@ -115,10 +115,10 @@ - - - - + + + + diff --git a/NzbDrone.Backbone/Quality/QualitySizeCollection.js b/NzbDrone.Backbone/Quality/QualitySizeCollection.js new file mode 100644 index 000000000..78033b751 --- /dev/null +++ b/NzbDrone.Backbone/Quality/QualitySizeCollection.js @@ -0,0 +1,6 @@ +define(['app', 'Quality/QualitySizeModel'], function () { + NzbDrone.Quality.QualitySizeCollection = Backbone.Collection.extend({ + model: NzbDrone.Quality.QualitySizeModel, + url: NzbDrone.Constants.ApiRoot + '/qualitysizes' + }); +}); \ No newline at end of file diff --git a/NzbDrone.Backbone/Quality/QualitySizeModel.js b/NzbDrone.Backbone/Quality/QualitySizeModel.js new file mode 100644 index 000000000..84c060a06 --- /dev/null +++ b/NzbDrone.Backbone/Quality/QualitySizeModel.js @@ -0,0 +1,17 @@ +define(['app'], function () { + NzbDrone.Quality.QualitySizeModel = Backbone.Model.extend({ + + initialize: function () { + this.validators = {}; + }, + + mutators: { + thirtyMinuteSize: function() { + return this.get('maxSize') * 30; + }, + sixtyMinuteSize: function(){ + return this.get('maxSize') * 60; + } + } + }); +}); \ No newline at end of file diff --git a/NzbDrone.Backbone/Quality/qualityTypeCollection.js b/NzbDrone.Backbone/Quality/qualityTypeCollection.js deleted file mode 100644 index 500cbdc0c..000000000 --- a/NzbDrone.Backbone/Quality/qualityTypeCollection.js +++ /dev/null @@ -1,4 +0,0 @@ -NzbDrone.Quality.QualityTypeCollection = Backbone.Collection.extend({ - model: NzbDrone.Quality.QualityTypeModel, - url: NzbDrone.Constants.ApiRoot + '/qualitytypes' -}); \ No newline at end of file diff --git a/NzbDrone.Backbone/Quality/qualityTypeModel.js b/NzbDrone.Backbone/Quality/qualityTypeModel.js deleted file mode 100644 index 92d2d7a4b..000000000 --- a/NzbDrone.Backbone/Quality/qualityTypeModel.js +++ /dev/null @@ -1,34 +0,0 @@ -NzbDrone.Quality.QualityTypeModel = Backbone.Model.extend({ - - initialize: function () { - this.validators = {}; - }, - - validateItem: function (key) { - return (this.validators[key]) ? this.validators[key](this.get(key)) : { isValid: true }; - }, - - // TODO: Implement Backbone's standard validate() method instead. - validateAll: function () { - - var messages = {}; - - for (var key in this.validators) { - if (this.validators.hasOwnProperty(key)) { - var check = this.validators[key](this.get(key)); - if (check.isValid === false) { - messages[key] = check.message; - } - } - } - - return _.size(messages) > 0 ? { isValid: false, messages: messages } : { isValid: true }; - }, - - defaults: { - Id: null, - Name: '', - MaxSize: 100, - MinSize: 0 - } -}); \ No newline at end of file diff --git a/NzbDrone.Backbone/Series/Index/SeriesItemView.js b/NzbDrone.Backbone/Series/Index/SeriesItemView.js index 3ec9eeeba..35ce172bf 100644 --- a/NzbDrone.Backbone/Series/Index/SeriesItemView.js +++ b/NzbDrone.Backbone/Series/Index/SeriesItemView.js @@ -30,7 +30,6 @@ define([ NzbDrone.ModelBinder.bind(this.model, this.el); }, - editSeries: function () { var view = new NzbDrone.Series.Edit.EditSeriesView({ model: this.model}); diff --git a/NzbDrone.Backbone/Settings/Naming/NamingView.js b/NzbDrone.Backbone/Settings/Naming/NamingView.js index 85d0bd07a..cfc60b81e 100644 --- a/NzbDrone.Backbone/Settings/Naming/NamingView.js +++ b/NzbDrone.Backbone/Settings/Naming/NamingView.js @@ -14,6 +14,11 @@ define([ tooltip: '[class^="help-inline"] i' }, + initialize: function(){ + //Listen to save event + this.bind + }, + onRender: function () { NzbDrone.ModelBinder.bind(this.model, this.el); this.ui.switch.bootstrapSwitch(); diff --git a/NzbDrone.Backbone/Settings/Quality/QualityLayout.js b/NzbDrone.Backbone/Settings/Quality/QualityLayout.js new file mode 100644 index 000000000..1f1eca63e --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualityLayout.js @@ -0,0 +1,41 @@ +define([ + 'app', + 'Quality/QualityProfileCollection', + 'Quality/QualitySizeCollection', + 'Settings/Quality/QualityView', + 'Settings/Quality/QualityProfileCollectionView', + 'Settings/Quality/QualitySizeCollectionView' +], + function (app, qualityProfileCollection) { + NzbDrone.Settings.Quality.QualityLayout = Backbone.Marionette.Layout.extend({ + template: 'Settings/Quality/QualityLayoutTemplate', + + regions: { + qualityStandard: '#quality-standard', + qualityProfile: '#quality-profile', + qualitySize: '#quality-size' + }, + + ui: { + + }, + + events: { + + }, + + initialize: function (options) { + this.settings = options.settings; + qualityProfileCollection.fetch(); + this.qualitySizeCollection = new NzbDrone.Quality.QualitySizeCollection(); + this.qualitySizeCollection.fetch(); + }, + + onRender: function () { + this.qualityStandard.show(new NzbDrone.Settings.Quality.QualityView({model: this.settings, qualityProfiles: qualityProfileCollection})); + this.qualityProfile.show(new NzbDrone.Settings.Quality.QualityProfileCollectionView({collection: this.qualityProfileCollection})); + this.qualitySize.show(new NzbDrone.Settings.Quality.QualitySizeCollectionView({collection: this.qualitySizeCollection})); + } + }); + }); + diff --git a/NzbDrone.Backbone/Settings/Quality/QualityLayoutTemplate.html b/NzbDrone.Backbone/Settings/Quality/QualityLayoutTemplate.html new file mode 100644 index 000000000..2c7e04bf8 --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualityLayoutTemplate.html @@ -0,0 +1,9 @@ +
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionTemplate.html b/NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionTemplate.html new file mode 100644 index 000000000..666e8e3d2 --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionTemplate.html @@ -0,0 +1,5 @@ +
+ Quality Profiles +
+ Quality Profiles will be edited here +
\ No newline at end of file diff --git a/NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionView.js b/NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionView.js new file mode 100644 index 000000000..1201279aa --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualityProfileCollectionView.js @@ -0,0 +1,22 @@ +'use strict'; + +define(['app', 'Settings/Quality/QualityProfileView'], function (app) { + NzbDrone.Settings.Quality.QualityProfileCollectionView = Backbone.Marionette.CompositeView.extend({ + itemView: NzbDrone.Settings.Quality.QualityProfileView, + itemViewContainer: '#quality-profiles-container', + template: 'Settings/Quality/QualityProfileCollectionTemplate', + + initialize: function (options) { + + }, + + ui:{ + + }, + + onCompositeCollectionRendered: function() + { + + } + }); +}); \ No newline at end of file diff --git a/NzbDrone.Backbone/Settings/Quality/QualityProfileView.js b/NzbDrone.Backbone/Settings/Quality/QualityProfileView.js new file mode 100644 index 000000000..8140f186e --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualityProfileView.js @@ -0,0 +1,46 @@ +'use strict'; + +define([ + 'app', + 'Quality/QualityProfileCollection' + +], function () { + + NzbDrone.Settings.QualityProfileView = Backbone.Marionette.ItemView.extend({ + template: 'Settings/Quality/QualityProfileTemplate', + 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 + }); + } + }); +}); diff --git a/NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionTemplate.html b/NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionTemplate.html new file mode 100644 index 000000000..5475511db --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionTemplate.html @@ -0,0 +1,4 @@ +
+ Quality Size Limits +
+
\ No newline at end of file diff --git a/NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionView.js b/NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionView.js new file mode 100644 index 000000000..8c7491f88 --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualitySizeCollectionView.js @@ -0,0 +1,22 @@ +'use strict'; + +define(['app', 'Settings/Quality/QualitySizeView'], function (app) { + NzbDrone.Settings.Quality.QualitySizeCollectionView = Backbone.Marionette.CompositeView.extend({ + itemView: NzbDrone.Settings.Quality.QualitySizeView, + itemViewContainer: '#quality-sizes-container', + template: 'Settings/Quality/QualitySizeCollectionTemplate', + + initialize: function () { + var test = 1; + }, + + ui:{ + + }, + + onCompositeCollectionRendered: function() + { + + } + }); +}); \ No newline at end of file diff --git a/NzbDrone.Backbone/Settings/Quality/QualitySizeTemplate.html b/NzbDrone.Backbone/Settings/Quality/QualitySizeTemplate.html new file mode 100644 index 000000000..f396bc742 --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualitySizeTemplate.html @@ -0,0 +1,6 @@ +{{name}} +
+ + +
+30 minute size: MB | 60 minute size: MB \ No newline at end of file diff --git a/NzbDrone.Backbone/Settings/Quality/QualitySizeView.js b/NzbDrone.Backbone/Settings/Quality/QualitySizeView.js new file mode 100644 index 000000000..d6d922305 --- /dev/null +++ b/NzbDrone.Backbone/Settings/Quality/QualitySizeView.js @@ -0,0 +1,48 @@ +'use strict'; + +define([ + 'app', + 'Quality/QualitySizeCollection' + +], function () { + + NzbDrone.Settings.Quality.QualitySizeView = Backbone.Marionette.ItemView.extend({ + template: 'Settings/Quality/QualitySizeTemplate', + + ui: { + slider: '.slider', + thirtyMinuteSize: '.thirty-minute-size', + sixtyMinuteSize: '.sixty-minute-size' + }, + + events: { + 'slide .slider': 'slide' + }, + + initialize: function (options) { + this.qualityProfileCollection = options.qualityProfiles; + }, + + onRender: function () { + NzbDrone.ModelBinder.bind(this.model, this.el); + + var self = this; + this.ui.slider.slider({ + min: 0, + max: 200, + step: 1, + value: self.model.get('maxSize'), + tooltip: 'hide' + }); + }, + + slide: function (e) { + var newSize = e.value; + + this.model.set({ maxSize: newSize, thirtyMinuteSize: newSize * 30, sixtyMinuteSize: newSize * 60 }); + + this.ui.thirtyMinuteSize.html(newSize * 30); + this.ui.sixtyMinuteSize.html(newSize * 60); + } + }); +}); diff --git a/NzbDrone.Backbone/Settings/Quality/QualityTemplate.html b/NzbDrone.Backbone/Settings/Quality/QualityTemplate.html index 9941dfdb1..5472d5e6e 100644 --- a/NzbDrone.Backbone/Settings/Quality/QualityTemplate.html +++ b/NzbDrone.Backbone/Settings/Quality/QualityTemplate.html @@ -1,3 +1,14 @@ -
- Quality settings will go here -
\ No newline at end of file + +
+ +
+ + + + +
+
diff --git a/NzbDrone.Backbone/Settings/Quality/QualityView.js b/NzbDrone.Backbone/Settings/Quality/QualityView.js index a5ea9dc80..20b2c1008 100644 --- a/NzbDrone.Backbone/Settings/Quality/QualityView.js +++ b/NzbDrone.Backbone/Settings/Quality/QualityView.js @@ -7,6 +7,12 @@ define([ NzbDrone.Settings.Quality.QualityView = Backbone.Marionette.ItemView.extend({ template: 'Settings/Quality/QualityTemplate', + className: 'form-horizontal', + + initialize: function(options) { + this.qualityProfileCollection = options.qualityProfiles; + this.model.set({ qualityProfiles: this.qualityProfileCollection }); + }, onRender: function () { NzbDrone.ModelBinder.bind(this.model, this.el); diff --git a/NzbDrone.Backbone/Settings/SettingsLayout.js b/NzbDrone.Backbone/Settings/SettingsLayout.js index effcf7ac9..65d02cce7 100644 --- a/NzbDrone.Backbone/Settings/SettingsLayout.js +++ b/NzbDrone.Backbone/Settings/SettingsLayout.js @@ -1,15 +1,14 @@ define([ 'app', - 'Quality/QualityProfileCollection', 'Settings/Naming/NamingView', - 'Settings/Quality/QualityView', + 'Settings/Quality/QualityLayout', 'Settings/Indexers/IndexersView', 'Settings/DownloadClient/DownloadClientView', 'Settings/Notifications/NotificationsView', 'Settings/System/SystemView', 'Settings/Misc/MiscView' ], - function (app, qualityProfileCollection) { + function (app) { NzbDrone.Settings.SettingsLayout = Backbone.Marionette.Layout.extend({ template: 'Settings/SettingsLayoutTemplate', @@ -120,10 +119,8 @@ }, onRender: function () { - qualityProfileCollection.fetch(); - this.naming.show(new NzbDrone.Settings.Naming.NamingView({model: this.settings})); - this.quality.show(new NzbDrone.Settings.Quality.QualityView({model: this.settings})); + this.quality.show(new NzbDrone.Settings.Quality.QualityLayout({settings: this.settings})); this.indexers.show(new NzbDrone.Settings.Indexers.IndexersView({model: this.settings})); this.downloadClient.show(new NzbDrone.Settings.DownloadClient.DownloadClientView({model: this.settings})); this.notifications.show(new NzbDrone.Settings.Notifications.NotificationsView({model: this.settings}));