You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	Quality Size knobbed, other quality changes
This commit is contained in:
		| @@ -21,7 +21,7 @@ module.exports = function (grunt) { | ||||
|             'UI/JsLibraries/jquery.js'                       : 'http://code.jquery.com/jquery.js', | ||||
|             'UI/JsLibraries/jquery.backstretch.js'           : 'http://raw.github.com/srobbin/jquery-backstretch/master/jquery.backstretch.js', | ||||
|             'UI/JsLibraries/jquery.signalR.js'               : 'https://raw.github.com/SignalR/SignalR/master/samples/Microsoft.AspNet.SignalR.Hosting.AspNet.Samples/Scripts/jquery.signalR.js', | ||||
|  | ||||
|             'UI/JsLibraries/jquery.knob'                     : 'https://raw.github.com/aterrien/jQuery-Knob/master/js/jquery.knob.js', | ||||
|  | ||||
|             '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', | ||||
|   | ||||
| @@ -131,6 +131,7 @@ | ||||
|     <Compile Include="Notifications\NotificationResource.cs" /> | ||||
|     <Compile Include="NzbDroneRestModule.cs" /> | ||||
|     <Compile Include="PagingResource.cs" /> | ||||
|     <Compile Include="Qualities\QualityProfileSchemaModule.cs" /> | ||||
|     <Compile Include="REST\BadRequestException.cs" /> | ||||
|     <Compile Include="REST\ResourceValidator.cs" /> | ||||
|     <Compile Include="REST\RestModule.cs" /> | ||||
| @@ -152,7 +153,7 @@ | ||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
|     <Compile Include="NzbDroneApiModule.cs" /> | ||||
|     <Compile Include="Qualities\QualityProfileResource.cs" /> | ||||
|     <Compile Include="Qualities\QualityProfilesModule.cs" /> | ||||
|     <Compile Include="Qualities\QualityProfileModule.cs" /> | ||||
|     <Compile Include="Qualities\QualitySizeResource.cs" /> | ||||
|     <Compile Include="Qualities\QualitySizeModule.cs" /> | ||||
|     <Compile Include="Extensions\RequestExtensions.cs" /> | ||||
|   | ||||
| @@ -16,14 +16,14 @@ namespace NzbDrone.Api.Qualities | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public class QualityProfilesModule : NzbDroneRestModule<QualityProfileResource> | ||||
|     public class QualityProfileModule : NzbDroneRestModule<QualityProfileResource> | ||||
|     { | ||||
|         private readonly QualityProfileService _qualityProvider; | ||||
|         private readonly QualityProfileService _qualityProfileService; | ||||
| 
 | ||||
|         public QualityProfilesModule(QualityProfileService qualityProvider) | ||||
|             : base("/qualityProfiles") | ||||
|         public QualityProfileModule(QualityProfileService qualityProfileService) | ||||
|             : base("/qualityprofiles") | ||||
|         { | ||||
|             _qualityProvider = qualityProvider; | ||||
|             _qualityProfileService = qualityProfileService; | ||||
| 
 | ||||
|             GetResourceAll = GetAll; | ||||
| 
 | ||||
| @@ -39,30 +39,30 @@ namespace NzbDrone.Api.Qualities | ||||
|         private QualityProfileResource Create(QualityProfileResource resource) | ||||
|         { | ||||
|             var model = resource.InjectTo<QualityProfile>(); | ||||
|             model = _qualityProvider.Add(model); | ||||
|             model = _qualityProfileService.Add(model); | ||||
|             return GetById(model.Id); | ||||
|         } | ||||
| 
 | ||||
|         private void DeleteProfile(int id) | ||||
|         { | ||||
|             _qualityProvider.Delete(id); | ||||
|             _qualityProfileService.Delete(id); | ||||
|         } | ||||
| 
 | ||||
|         private QualityProfileResource Update(QualityProfileResource resource) | ||||
|         { | ||||
|             var model = resource.InjectTo<QualityProfile>(); | ||||
|             _qualityProvider.Update(model); | ||||
|             _qualityProfileService.Update(model); | ||||
|             return GetById(resource.Id); | ||||
|         } | ||||
| 
 | ||||
|         private QualityProfileResource GetById(int id) | ||||
|         { | ||||
|             return QualityToResource(_qualityProvider.Get(id)); | ||||
|             return QualityToResource(_qualityProfileService.Get(id)); | ||||
|         } | ||||
| 
 | ||||
|         private List<QualityProfileResource> GetAll() | ||||
|         { | ||||
|             var allProfiles = _qualityProvider.All(); | ||||
|             var allProfiles = _qualityProfileService.All(); | ||||
| 
 | ||||
| 
 | ||||
|             var profiles = allProfiles.Select(QualityToResource).ToList(); | ||||
							
								
								
									
										41
									
								
								NzbDrone.Api/Qualities/QualityProfileSchemaModule.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								NzbDrone.Api/Qualities/QualityProfileSchemaModule.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using NzbDrone.Core.Datastore; | ||||
| using NzbDrone.Core.Qualities; | ||||
| using NzbDrone.Api.Mapping; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace NzbDrone.Api.Qualities | ||||
| { | ||||
|     public class QualityProfileSchemaModule : NzbDroneRestModule<QualityProfileResource> | ||||
|     { | ||||
|         public QualityProfileSchemaModule() | ||||
|             : base("/qualityprofiles/schema") | ||||
|         { | ||||
|             GetResourceAll = GetAll; | ||||
|         } | ||||
|  | ||||
|         private List<QualityProfileResource> GetAll() | ||||
|         { | ||||
|             var profile = new QualityProfile(); | ||||
|             profile.Cutoff = Quality.Unknown; | ||||
|             profile.Allowed = new List<Quality>(); | ||||
|  | ||||
|             return new List<QualityProfileResource>{ QualityToResource(profile)}; | ||||
|         } | ||||
|  | ||||
|         private static QualityProfileResource QualityToResource(QualityProfile profile) | ||||
|         { | ||||
|             return new QualityProfileResource | ||||
|                 { | ||||
|                     Available = Quality.All() | ||||
|                         .Where(c => !profile.Allowed.Any(q => c.Id == q.Id)) | ||||
|                         .InjectTo<List<QualityResource>>(), | ||||
|  | ||||
|                     Allowed = profile.Allowed.InjectTo<List<QualityResource>>(), | ||||
|                     Name = profile.Name, | ||||
|                     Id = profile.Id | ||||
|                 }; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										335
									
								
								UI/JsLibraries/bootstrap.slider.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										335
									
								
								UI/JsLibraries/bootstrap.slider.js
									
									
									
									
										vendored
									
									
								
							| @@ -1,335 +0,0 @@ | ||||
| /* ========================================================= | ||||
|  * 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 = $('<div class="slider">'+ | ||||
| 							'<div class="slider-track">'+ | ||||
| 								'<div class="slider-selection"></div>'+ | ||||
| 								'<div class="slider-handle"></div>'+ | ||||
| 								'<div class="slider-handle"></div>'+ | ||||
| 							'</div>'+ | ||||
| 							'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+ | ||||
| 						'</div>') | ||||
| 							.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 ); | ||||
							
								
								
									
										671
									
								
								UI/JsLibraries/jquery.knob.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										671
									
								
								UI/JsLibraries/jquery.knob.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,671 @@ | ||||
| /*!jQuery Knob*/ | ||||
| /** | ||||
|  * Downward compatible, touchable dial | ||||
|  * | ||||
|  * Version: 1.2.0 (15/07/2012) | ||||
|  * Requires: jQuery v1.7+ | ||||
|  * | ||||
|  * Copyright (c) 2012 Anthony Terrien | ||||
|  * Under MIT and GPL licenses: | ||||
|  *  http://www.opensource.org/licenses/mit-license.php | ||||
|  *  http://www.gnu.org/licenses/gpl.html | ||||
|  * | ||||
|  * Thanks to vor, eskimoblood, spiffistan, FabrizioC | ||||
|  */ | ||||
| (function($) { | ||||
|  | ||||
|     /** | ||||
|      * Kontrol library | ||||
|      */ | ||||
|     "use strict"; | ||||
|  | ||||
|     /** | ||||
|      * Definition of globals and core | ||||
|      */ | ||||
|     var k = {}, // kontrol | ||||
|         max = Math.max, | ||||
|         min = Math.min; | ||||
|  | ||||
|     k.c = {}; | ||||
|     k.c.d = $(document); | ||||
|     k.c.t = function (e) { | ||||
|         return e.originalEvent.touches.length - 1; | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|      * Kontrol Object | ||||
|      * | ||||
|      * Definition of an abstract UI control | ||||
|      * | ||||
|      * Each concrete component must call this one. | ||||
|      * <code> | ||||
|      * k.o.call(this); | ||||
|      * </code> | ||||
|      */ | ||||
|     k.o = function () { | ||||
|         var s = this; | ||||
|  | ||||
|         this.o = null; // array of options | ||||
|         this.$ = null; // jQuery wrapped element | ||||
|         this.i = null; // mixed HTMLInputElement or array of HTMLInputElement | ||||
|         this.g = null; // 2D graphics context for 'pre-rendering' | ||||
|         this.v = null; // value ; mixed array or integer | ||||
|         this.cv = null; // change value ; not commited value | ||||
|         this.x = 0; // canvas x position | ||||
|         this.y = 0; // canvas y position | ||||
|         this.$c = null; // jQuery canvas element | ||||
|         this.c = null; // rendered canvas context | ||||
|         this.t = 0; // touches index | ||||
|         this.isInit = false; | ||||
|         this.fgColor = null; // main color | ||||
|         this.pColor = null; // previous color | ||||
|         this.dH = null; // draw hook | ||||
|         this.cH = null; // change hook | ||||
|         this.eH = null; // cancel hook | ||||
|         this.rH = null; // release hook | ||||
|  | ||||
|         this.run = function () { | ||||
|             var cf = function (e, conf) { | ||||
|                 var k; | ||||
|                 for (k in conf) { | ||||
|                     s.o[k] = conf[k]; | ||||
|                 } | ||||
|                 s.init(); | ||||
|                 s._configure() | ||||
|                  ._draw(); | ||||
|             }; | ||||
|  | ||||
|             if(this.$.data('kontroled')) return; | ||||
|             this.$.data('kontroled', true); | ||||
|  | ||||
|             this.extend(); | ||||
|             this.o = $.extend( | ||||
|                 { | ||||
|                     // Config | ||||
|                     min : this.$.data('min') || 0, | ||||
|                     max : this.$.data('max') || 100, | ||||
|                     stopper : true, | ||||
|                     readOnly : this.$.data('readonly'), | ||||
|  | ||||
|                     // UI | ||||
|                     cursor : (this.$.data('cursor') === true && 30) | ||||
|                                 || this.$.data('cursor') | ||||
|                                 || 0, | ||||
|                     thickness : this.$.data('thickness') || 0.35, | ||||
|                     lineCap : this.$.data('linecap') || 'butt', | ||||
|                     width : this.$.data('width') || 200, | ||||
|                     height : this.$.data('height') || 200, | ||||
|                     displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'), | ||||
|                     displayPrevious : this.$.data('displayprevious'), | ||||
|                     fgColor : this.$.data('fgcolor') || '#87CEEB', | ||||
|                     inputColor: this.$.data('inputcolor') || this.$.data('fgcolor') || '#87CEEB', | ||||
|                     inline : false, | ||||
|                     step : this.$.data('step') || 1, | ||||
|  | ||||
|                     // Hooks | ||||
|                     draw : null, // function () {} | ||||
|                     change : null, // function (value) {} | ||||
|                     cancel : null, // function () {} | ||||
|                     release : null, // function (value) {} | ||||
|                     error : null // function () {} | ||||
|                 }, this.o | ||||
|             ); | ||||
|  | ||||
|             // routing value | ||||
|             if(this.$.is('fieldset')) { | ||||
|  | ||||
|                 // fieldset = array of integer | ||||
|                 this.v = {}; | ||||
|                 this.i = this.$.find('input') | ||||
|                 this.i.each(function(k) { | ||||
|                     var $this = $(this); | ||||
|                     s.i[k] = $this; | ||||
|                     s.v[k] = $this.val(); | ||||
|  | ||||
|                     $this.bind( | ||||
|                         'change' | ||||
|                         , function () { | ||||
|                             var val = {}; | ||||
|                             val[k] = $this.val(); | ||||
|                             s.val(val); | ||||
|                         } | ||||
|                     ); | ||||
|                 }); | ||||
|                 this.$.find('legend').remove(); | ||||
|  | ||||
|             } else { | ||||
|                 // input = integer | ||||
|                 this.i = this.$; | ||||
|                 this.v = this.$.val(); | ||||
|                 (this.v == '') && (this.v = this.o.min); | ||||
|  | ||||
|                 this.$.bind( | ||||
|                     'change' | ||||
|                     , function () { | ||||
|                         s.val(s._validate(s.$.val())); | ||||
|                     } | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             (!this.o.displayInput) && this.$.hide(); | ||||
|  | ||||
|             this.$c = $('<canvas width="' + | ||||
|                             this.o.width + 'px" height="' + | ||||
|                             this.o.height + 'px"></canvas>'); | ||||
|              | ||||
|             this.c = this.$c[0].getContext? this.$c[0].getContext('2d') : null; | ||||
| 			 | ||||
|             if (!this.c) { | ||||
|                 this.o.error && this.o.error(); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.$ | ||||
|                 .wrap($('<div style="' + (this.o.inline ? 'display:inline;' : '') + | ||||
|                         'width:' + this.o.width + 'px;height:' + | ||||
|                         this.o.height + 'px;"></div>')) | ||||
|                 .before(this.$c); | ||||
|  | ||||
|             if (this.v instanceof Object) { | ||||
|                 this.cv = {}; | ||||
|                 this.copy(this.v, this.cv); | ||||
|             } else { | ||||
|                 this.cv = this.v; | ||||
|             } | ||||
|  | ||||
|             this.$ | ||||
|                 .bind("configure", cf) | ||||
|                 .parent() | ||||
|                 .bind("configure", cf); | ||||
|  | ||||
|             this._listen() | ||||
|                 ._configure() | ||||
|                 ._xy() | ||||
|                 .init(); | ||||
|  | ||||
|             this.isInit = true; | ||||
|  | ||||
|             this._draw(); | ||||
|  | ||||
|             return this; | ||||
|         }; | ||||
|  | ||||
|         this._draw = function () { | ||||
|  | ||||
|             // canvas pre-rendering | ||||
|             var d = true, | ||||
|                 c = document.createElement('canvas'); | ||||
|  | ||||
|             c.width = s.o.width; | ||||
|             c.height = s.o.height; | ||||
|             s.g = c.getContext('2d'); | ||||
|  | ||||
|             s.clear(); | ||||
|  | ||||
|             s.dH | ||||
|             && (d = s.dH()); | ||||
|  | ||||
|             (d !== false) && s.draw(); | ||||
|  | ||||
|             s.c.drawImage(c, 0, 0); | ||||
|             c = null; | ||||
|         }; | ||||
|  | ||||
|         this._touch = function (e) { | ||||
|  | ||||
|             var touchMove = function (e) { | ||||
|  | ||||
|                 var v = s.xy2val( | ||||
|                             e.originalEvent.touches[s.t].pageX, | ||||
|                             e.originalEvent.touches[s.t].pageY | ||||
|                             ); | ||||
|  | ||||
|                 if (v == s.cv) return; | ||||
|  | ||||
|                 if ( | ||||
|                     s.cH | ||||
|                     && (s.cH(v) === false) | ||||
|                 ) return; | ||||
|  | ||||
|  | ||||
|                 s.change(s._validate(v)); | ||||
|                 s.$.trigger('change', v); | ||||
|                 s._draw(); | ||||
|             }; | ||||
|  | ||||
|             // get touches index | ||||
|             this.t = k.c.t(e); | ||||
|  | ||||
|             // First touch | ||||
|             touchMove(e); | ||||
|  | ||||
|             // Touch events listeners | ||||
|             k.c.d | ||||
|                 .bind("touchmove.k", touchMove) | ||||
|                 .bind( | ||||
|                     "touchend.k" | ||||
|                     , function () { | ||||
|                         k.c.d.unbind('touchmove.k touchend.k'); | ||||
|  | ||||
|                         if ( | ||||
|                             s.rH | ||||
|                             && (s.rH(s.cv) === false) | ||||
|                         ) return; | ||||
|  | ||||
|                         s.val(s.cv); | ||||
|                     } | ||||
|                 ); | ||||
|  | ||||
|             return this; | ||||
|         }; | ||||
|  | ||||
|         this._mouse = function (e) { | ||||
|  | ||||
|             var mouseMove = function (e) { | ||||
|                 var v = s.xy2val(e.pageX, e.pageY); | ||||
|                 if (v == s.cv) return; | ||||
|  | ||||
|                 if ( | ||||
|                     s.cH | ||||
|                     && (s.cH(v) === false) | ||||
|                 ) return; | ||||
|  | ||||
|                 s.change(s._validate(v)); | ||||
|                 s.$.trigger('change', v); | ||||
|                 s._draw(); | ||||
|             }; | ||||
|  | ||||
|             // First click | ||||
|             mouseMove(e); | ||||
|  | ||||
|             // Mouse events listeners | ||||
|             k.c.d | ||||
|                 .bind("mousemove.k", mouseMove) | ||||
|                 .bind( | ||||
|                     // Escape key cancel current change | ||||
|                     "keyup.k" | ||||
|                     , function (e) { | ||||
|                         if (e.keyCode === 27) { | ||||
|                             k.c.d.unbind("mouseup.k mousemove.k keyup.k"); | ||||
|  | ||||
|                             if ( | ||||
|                                 s.eH | ||||
|                                 && (s.eH() === false) | ||||
|                             ) return; | ||||
|  | ||||
|                             s.cancel(); | ||||
|                         } | ||||
|                     } | ||||
|                 ) | ||||
|                 .bind( | ||||
|                     "mouseup.k" | ||||
|                     , function (e) { | ||||
|                         k.c.d.unbind('mousemove.k mouseup.k keyup.k'); | ||||
|  | ||||
|                         if ( | ||||
|                             s.rH | ||||
|                             && (s.rH(s.cv) === false) | ||||
|                         ) return; | ||||
|  | ||||
|                         s.val(s.cv); | ||||
|                     } | ||||
|                 ); | ||||
|  | ||||
|             return this; | ||||
|         }; | ||||
|  | ||||
|         this._xy = function () { | ||||
|             var o = this.$c.offset(); | ||||
|             this.x = o.left; | ||||
|             this.y = o.top; | ||||
|             return this; | ||||
|         }; | ||||
|  | ||||
|         this._listen = function () { | ||||
|  | ||||
|             if (!this.o.readOnly) { | ||||
|                 this.$c | ||||
|                     .bind( | ||||
|                         "mousedown" | ||||
|                         , function (e) { | ||||
|                             e.preventDefault(); | ||||
|                             s._xy()._mouse(e); | ||||
|                          } | ||||
|                     ) | ||||
|                     .bind( | ||||
|                         "touchstart" | ||||
|                         , function (e) { | ||||
|                             e.preventDefault(); | ||||
|                             s._xy()._touch(e); | ||||
|                          } | ||||
|                     ); | ||||
|                 this.listen(); | ||||
|             } else { | ||||
|                 this.$.attr('readonly', 'readonly'); | ||||
|             } | ||||
|  | ||||
|             return this; | ||||
|         }; | ||||
|  | ||||
|         this._configure = function () { | ||||
|  | ||||
|             // Hooks | ||||
|             if (this.o.draw) this.dH = this.o.draw; | ||||
|             if (this.o.change) this.cH = this.o.change; | ||||
|             if (this.o.cancel) this.eH = this.o.cancel; | ||||
|             if (this.o.release) this.rH = this.o.release; | ||||
|  | ||||
|             if (this.o.displayPrevious) { | ||||
|                 this.pColor = this.h2rgba(this.o.fgColor, "0.4"); | ||||
|                 this.fgColor = this.h2rgba(this.o.fgColor, "0.6"); | ||||
|             } else { | ||||
|                 this.fgColor = this.o.fgColor; | ||||
|             } | ||||
|  | ||||
|             return this; | ||||
|         }; | ||||
|  | ||||
|         this._clear = function () { | ||||
|             this.$c[0].width = this.$c[0].width; | ||||
|         }; | ||||
|  | ||||
|         this._validate = function(v) { | ||||
|             return (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step; | ||||
|         }; | ||||
|  | ||||
|         // Abstract methods | ||||
|         this.listen = function () {}; // on start, one time | ||||
|         this.extend = function () {}; // each time configure triggered | ||||
|         this.init = function () {}; // each time configure triggered | ||||
|         this.change = function (v) {}; // on change | ||||
|         this.val = function (v) {}; // on release | ||||
|         this.xy2val = function (x, y) {}; // | ||||
|         this.draw = function () {}; // on change / on release | ||||
|         this.clear = function () { this._clear(); }; | ||||
|  | ||||
|         // Utils | ||||
|         this.h2rgba = function (h, a) { | ||||
|             var rgb; | ||||
|             h = h.substring(1,7) | ||||
|             rgb = [parseInt(h.substring(0,2),16) | ||||
|                    ,parseInt(h.substring(2,4),16) | ||||
|                    ,parseInt(h.substring(4,6),16)]; | ||||
|             return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")"; | ||||
|         }; | ||||
|  | ||||
|         this.copy = function (f, t) { | ||||
|             for (var i in f) { t[i] = f[i]; } | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * k.Dial | ||||
|      */ | ||||
|     k.Dial = function () { | ||||
|         k.o.call(this); | ||||
|  | ||||
|         this.startAngle = null; | ||||
|         this.xy = null; | ||||
|         this.radius = null; | ||||
|         this.lineWidth = null; | ||||
|         this.cursorExt = null; | ||||
|         this.w2 = null; | ||||
|         this.PI2 = 2*Math.PI; | ||||
|  | ||||
|         this.extend = function () { | ||||
|             this.o = $.extend( | ||||
|                 { | ||||
|                     bgColor : this.$.data('bgcolor') || '#EEEEEE', | ||||
|                     angleOffset : this.$.data('angleoffset') || 0, | ||||
|                     angleArc : this.$.data('anglearc') || 360, | ||||
|                     inline : true | ||||
|                 }, this.o | ||||
|             ); | ||||
|         }; | ||||
|  | ||||
|         this.val = function (v) { | ||||
|             if (null != v) { | ||||
|                 this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v; | ||||
|                 this.v = this.cv; | ||||
|                 this.$.val(this.v); | ||||
|                 this._draw(); | ||||
|             } else { | ||||
|                 return this.v; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         this.xy2val = function (x, y) { | ||||
|             var a, ret; | ||||
|  | ||||
|             a = Math.atan2( | ||||
|                         x - (this.x + this.w2) | ||||
|                         , - (y - this.y - this.w2) | ||||
|                     ) - this.angleOffset; | ||||
|  | ||||
|             if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) { | ||||
|                 // if isset angleArc option, set to min if .5 under min | ||||
|                 a = 0; | ||||
|             } else if (a < 0) { | ||||
|                 a += this.PI2; | ||||
|             } | ||||
|  | ||||
|             ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc)) | ||||
|                     + this.o.min; | ||||
|  | ||||
|             this.o.stopper | ||||
|             && (ret = max(min(ret, this.o.max), this.o.min)); | ||||
|  | ||||
|             return ret; | ||||
|         }; | ||||
|  | ||||
|         this.listen = function () { | ||||
|             // bind MouseWheel | ||||
|             var s = this, | ||||
|                 mw = function (e) { | ||||
|                             e.preventDefault(); | ||||
|                             var ori = e.originalEvent | ||||
|                                 ,deltaX = ori.detail || ori.wheelDeltaX | ||||
|                                 ,deltaY = ori.detail || ori.wheelDeltaY | ||||
|                                 ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? s.o.step : deltaX<0 || deltaY<0 ? -s.o.step : 0); | ||||
|  | ||||
|                             if ( | ||||
|                                 s.cH | ||||
|                                 && (s.cH(v) === false) | ||||
|                             ) return; | ||||
|  | ||||
|                             s.val(v); | ||||
|                         } | ||||
|                 , kval, to, m = 1, kv = {37:-s.o.step, 38:s.o.step, 39:s.o.step, 40:-s.o.step}; | ||||
|  | ||||
|             this.$ | ||||
|                 .bind( | ||||
|                     "keydown" | ||||
|                     ,function (e) { | ||||
|                         var kc = e.keyCode; | ||||
|  | ||||
|                         // numpad support | ||||
|                         if(kc >= 96 && kc <= 105) { | ||||
|                             kc = e.keyCode = kc - 48; | ||||
|                         } | ||||
|  | ||||
|                         kval = parseInt(String.fromCharCode(kc)); | ||||
|  | ||||
|                         if (isNaN(kval)) { | ||||
|  | ||||
|                             (kc !== 13)         // enter | ||||
|                             && (kc !== 8)       // bs | ||||
|                             && (kc !== 9)       // tab | ||||
|                             && (kc !== 189)     // - | ||||
|                             && e.preventDefault(); | ||||
|  | ||||
|                             // arrows | ||||
|                             if ($.inArray(kc,[37,38,39,40]) > -1) { | ||||
|                                 e.preventDefault(); | ||||
|  | ||||
|                                 var v = parseInt(s.$.val()) + kv[kc] * m; | ||||
|  | ||||
|                                 s.o.stopper | ||||
|                                 && (v = max(min(v, s.o.max), s.o.min)); | ||||
|  | ||||
|                                 s.change(v); | ||||
|                                 s.$.trigger('change', v); | ||||
|                                 s._draw(); | ||||
|  | ||||
|                                 // long time keydown speed-up | ||||
|                                 to = window.setTimeout( | ||||
|                                     function () { m*=2; } | ||||
|                                     ,30 | ||||
|                                 ); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 ) | ||||
|                 .bind( | ||||
|                     "keyup" | ||||
|                     ,function (e) { | ||||
|                         if (isNaN(kval)) { | ||||
|                             if (to) { | ||||
|                                 window.clearTimeout(to); | ||||
|                                 to = null; | ||||
|                                 m = 1; | ||||
|                                 s.val(s.$.val()); | ||||
|                             } | ||||
|                         } else { | ||||
|                             // kval postcond | ||||
|                             (s.$.val() > s.o.max && s.$.val(s.o.max)) | ||||
|                             || (s.$.val() < s.o.min && s.$.val(s.o.min)); | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 ); | ||||
|  | ||||
|             this.$c.bind("mousewheel DOMMouseScroll", mw); | ||||
|             this.$.bind("mousewheel DOMMouseScroll", mw) | ||||
|         }; | ||||
|  | ||||
|         this.init = function () { | ||||
|  | ||||
|             if ( | ||||
|                 this.v < this.o.min | ||||
|                 || this.v > this.o.max | ||||
|             ) this.v = this.o.min; | ||||
|  | ||||
|             this.$.val(this.v); | ||||
|             this.w2 = this.o.width / 2; | ||||
|             this.cursorExt = this.o.cursor / 100; | ||||
|             this.xy = this.w2; | ||||
|             this.lineWidth = this.xy * this.o.thickness; | ||||
|             this.lineCap = this.o.lineCap; | ||||
|             this.radius = this.xy - this.lineWidth / 2; | ||||
|  | ||||
|             this.o.angleOffset | ||||
|             && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset); | ||||
|  | ||||
|             this.o.angleArc | ||||
|             && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc); | ||||
|  | ||||
|             // deg to rad | ||||
|             this.angleOffset = this.o.angleOffset * Math.PI / 180; | ||||
|             this.angleArc = this.o.angleArc * Math.PI / 180; | ||||
|  | ||||
|             // compute start and end angles | ||||
|             this.startAngle = 1.5 * Math.PI + this.angleOffset; | ||||
|             this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc; | ||||
|  | ||||
|             var s = max( | ||||
|                             String(Math.abs(this.o.max)).length | ||||
|                             , String(Math.abs(this.o.min)).length | ||||
|                             , 2 | ||||
|                             ) + 2; | ||||
|  | ||||
|             this.o.displayInput | ||||
|                 && this.i.css({ | ||||
|                         'width' : ((this.o.width / 2 + 4) >> 0) + 'px' | ||||
|                         ,'height' : ((this.o.width / 3) >> 0) + 'px' | ||||
|                         ,'position' : 'absolute' | ||||
|                         ,'vertical-align' : 'middle' | ||||
|                         ,'margin-top' : ((this.o.width / 3) >> 0) + 'px' | ||||
|                         ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px' | ||||
|                         ,'border' : 0 | ||||
|                         ,'background' : 'none' | ||||
|                         ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial' | ||||
|                         ,'text-align' : 'center' | ||||
|                         ,'color' : this.o.inputColor || this.o.fgColor | ||||
|                         ,'padding' : '0px' | ||||
|                         ,'-webkit-appearance': 'none' | ||||
|                         }) | ||||
|                 || this.i.css({ | ||||
|                         'width' : '0px' | ||||
|                         ,'visibility' : 'hidden' | ||||
|                         }); | ||||
|         }; | ||||
|  | ||||
|         this.change = function (v) { | ||||
|             this.cv = v; | ||||
|             this.$.val(v); | ||||
|         }; | ||||
|  | ||||
|         this.angle = function (v) { | ||||
|             return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min); | ||||
|         }; | ||||
|  | ||||
|         this.draw = function () { | ||||
|  | ||||
|             var c = this.g,                 // context | ||||
|                 a = this.angle(this.cv)    // Angle | ||||
|                 , sat = this.startAngle     // Start angle | ||||
|                 , eat = sat + a             // End angle | ||||
|                 , sa, ea                    // Previous angles | ||||
|                 , r = 1; | ||||
|  | ||||
|             c.lineWidth = this.lineWidth; | ||||
|  | ||||
|             c.lineCap = this.lineCap; | ||||
|  | ||||
|             this.o.cursor | ||||
|                 && (sat = eat - this.cursorExt) | ||||
|                 && (eat = eat + this.cursorExt); | ||||
|  | ||||
|             c.beginPath(); | ||||
|                 c.strokeStyle = this.o.bgColor; | ||||
|                 c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true); | ||||
|             c.stroke(); | ||||
|  | ||||
|             if (this.o.displayPrevious) { | ||||
|                 ea = this.startAngle + this.angle(this.v); | ||||
|                 sa = this.startAngle; | ||||
|                 this.o.cursor | ||||
|                     && (sa = ea - this.cursorExt) | ||||
|                     && (ea = ea + this.cursorExt); | ||||
|  | ||||
|                 c.beginPath(); | ||||
|                     c.strokeStyle = this.pColor; | ||||
|                     c.arc(this.xy, this.xy, this.radius, sa, ea, false); | ||||
|                 c.stroke(); | ||||
|                 r = (this.cv == this.v); | ||||
|             } | ||||
|  | ||||
|             c.beginPath(); | ||||
|                 c.strokeStyle = r ? this.o.fgColor : this.fgColor ; | ||||
|                 c.arc(this.xy, this.xy, this.radius, sat, eat, false); | ||||
|             c.stroke(); | ||||
|         }; | ||||
|  | ||||
|         this.cancel = function () { | ||||
|             this.val(this.v); | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     $.fn.dial = $.fn.knob = function (o) { | ||||
|         return this.each( | ||||
|             function () { | ||||
|                 var d = new k.Dial(); | ||||
|                 d.o = o; | ||||
|                 d.$ = $(this); | ||||
|                 d.run(); | ||||
|             } | ||||
|         ).parent(); | ||||
|     }; | ||||
|  | ||||
| })(jQuery); | ||||
| @@ -1,4 +1,5 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
|  | ||||
| define( | ||||
|     [ | ||||
|         'backbone' | ||||
|   | ||||
| @@ -14,7 +14,6 @@ define(['app', | ||||
|                 'click .x-add': 'openSchemaModal' | ||||
|             }, | ||||
|  | ||||
|  | ||||
|             openSchemaModal: function () { | ||||
|                 var self = this; | ||||
|                 //TODO: Is there a better way to deal with changing URLs? | ||||
|   | ||||
| @@ -1,6 +1,10 @@ | ||||
| <div class="modal-header"> | ||||
|     <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> | ||||
|     <h3>Edit: Quality Profile</h3> | ||||
|     {{#if id}} | ||||
|         <h3>Edit</h3> | ||||
|     {{else}} | ||||
|         <h3>Add</h3> | ||||
|     {{/if}} | ||||
| </div> | ||||
| <div class="modal-body"> | ||||
|     <div class="form-horizontal"> | ||||
| @@ -16,9 +20,9 @@ | ||||
|         <div class="control-group"> | ||||
|             <label class="control-label">Cutoff</label> | ||||
|             <div class="controls"> | ||||
|                 <select class="x-cutoff" name="cutoff"> | ||||
|                 <select class="x-cutoff" name="cutoff.id"> | ||||
|                     {{#each allowed}} | ||||
|                     <option value="{{id}}">{{name}}</option> | ||||
|                         <option value="{{id}}">{{name}}</option> | ||||
|                     {{/each}} | ||||
|                 </select> | ||||
|                 <span class="help-inline"> | ||||
| @@ -47,7 +51,9 @@ | ||||
|     </div> | ||||
| </div> | ||||
| <div class="modal-footer"> | ||||
|     <button class="btn btn-danger pull-left x-remove">delete</button> | ||||
|     {{#if id}} | ||||
|         <button class="btn btn-danger pull-left x-remove">delete</button> | ||||
|     {{/if}} | ||||
|     <button class="btn" data-dismiss="modal">cancel</button> | ||||
|     <button class="btn btn-primary x-save">save</button> | ||||
| </div> | ||||
|   | ||||
| @@ -4,12 +4,20 @@ define(['app', 'marionette', 'Mixins/AsModelBoundView'], function (App, Marionet | ||||
|     var view = Marionette.ItemView.extend({ | ||||
|         template: 'Settings/Quality/Profile/EditQualityProfileTemplate', | ||||
|  | ||||
|         ui: { | ||||
|             cutoff: '.x-cutoff' | ||||
|         }, | ||||
|  | ||||
|         events: { | ||||
|             'click .x-save'             : 'saveQualityProfile', | ||||
|             '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; | ||||
| @@ -39,19 +47,25 @@ define(['app', 'marionette', 'Mixins/AsModelBoundView'], function (App, Marionet | ||||
|                 throw 'couldnt find quality id ' + qualityId; | ||||
|             } | ||||
|  | ||||
|  | ||||
|             this.model.set('available', availableCollection.toJSON()); | ||||
|             this.model.set('allowed', allowedCollection.toJSON()); | ||||
|  | ||||
|             this.render(); | ||||
|         }, | ||||
|  | ||||
|         saveQualityProfile: function () { | ||||
|             //Todo: Make sure model is updated with Allowed, Cutoff, Name | ||||
|         _saveQualityProfile: function () { | ||||
|             var self = this; | ||||
|             var cutoff = _.findWhere(this.model.get('allowed'), { id: parseInt(this.ui.cutoff.val())}); | ||||
|             this.model.set('cutoff', cutoff); | ||||
|  | ||||
|             this.model.save(); | ||||
|             this.trigger('saved'); | ||||
|             App.modalRegion.closeModal(); | ||||
|             var promise = this.model.save(); | ||||
|  | ||||
|             if (promise) { | ||||
|                 promise.done(function () { | ||||
|                     self.profileCollection.add(self.model, { merge: true }); | ||||
|                     App.modalRegion.closeModal(); | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| <fieldset> | ||||
|     <legend>Quality Profiles</legend> | ||||
|     <ul class="quality-profiles"></ul> | ||||
|     <div class="row"> | ||||
|         <div class="span12"> | ||||
|             <button class="btn btn-success x-add">Add Profile</button> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="row"> | ||||
|         <div class="span12"> | ||||
|             <ul class="quality-profiles"></ul> | ||||
|         </div> | ||||
|     </div> | ||||
| </fieldset> | ||||
| @@ -1,9 +1,35 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| define(['marionette', 'Settings/Quality/Profile/QualityProfileView'], function (Marionette, QualityProfileView) { | ||||
| 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' | ||||
|         template         : 'Settings/Quality/Profile/QualityProfileCollectionTemplate', | ||||
|  | ||||
|         events: { | ||||
|             'click .x-add': '_addProfile' | ||||
|         }, | ||||
|  | ||||
|         _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.ApiRoot + '/qualityprofiles/schema' | ||||
|         }); | ||||
|     }); | ||||
| @@ -1,9 +1,9 @@ | ||||
| <div class="quality-profile-item"> | ||||
|     <div> | ||||
|         <h2>{{name}}</h2> | ||||
|         <h2 name="name"></h2> | ||||
|         <span class="btn-group pull-right"> | ||||
|             <button class="btn btn-mini btn-danger x-delete">Delete</button> | ||||
|             <button class="btn btn-mini x-edit">Edit</button> | ||||
|             <button class="btn btn-mini btn-danger x-delete">Delete</button> | ||||
|         </span> | ||||
|     </div> | ||||
|  | ||||
|   | ||||
| @@ -24,8 +24,12 @@ define( | ||||
|                 'click .x-delete': '_deleteProfile' | ||||
|             }, | ||||
|  | ||||
|             initialize: function () { | ||||
|                 this.listenTo(this.model, 'sync', this.render); | ||||
|             }, | ||||
|  | ||||
|             _editProfile: function () { | ||||
|                 var view = new EditProfileView({ model: this.model}); | ||||
|                 var view = new EditProfileView({ model: this.model, profileCollection: this.model.collection }); | ||||
|                 App.modalRegion.show(view); | ||||
|             }, | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
|  | ||||
| define( | ||||
|     [ | ||||
|         'marionette', | ||||
| @@ -11,7 +12,6 @@ define( | ||||
|             template: 'Settings/Quality/QualityLayoutTemplate', | ||||
|  | ||||
|             regions: { | ||||
|                 qualityStandard: '#quality-standard', | ||||
|                 qualityProfile : '#quality-profile', | ||||
|                 qualitySize    : '#quality-size' | ||||
|             }, | ||||
|   | ||||
| @@ -1,7 +1,4 @@ | ||||
| <div class="row"> | ||||
|     <div class="span12" id="quality-standard"/> | ||||
| </div> | ||||
| <div class="row"> | ||||
|     <div class="span12" id="quality-profile"/> | ||||
| </div> | ||||
| <div class="row"> | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| <fieldset> | ||||
|     <legend>Quality Size Limits</legend> | ||||
|     <div id="quality-sizes-container"/> | ||||
|     <ul class="quality-sizes"/> | ||||
| </fieldset> | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| define(['marionette', 'Settings/Quality/Size/QualitySizeView'], function (Marionette, QualitySizeView) { | ||||
|     return Marionette.CompositeView.extend({ | ||||
|         itemView         : QualitySizeView, | ||||
|         itemViewContainer: '#quality-sizes-container', | ||||
|         itemViewContainer: '.quality-sizes', | ||||
|         template         : 'Settings/Quality/Size/QualitySizeCollectionTemplate' | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| <b>{{name}}</b> | ||||
| <div class="quality-slider-container"> | ||||
|     <input type="text" class="span4 slider"/> | ||||
| <div class="quality-size-item"> | ||||
|     <h2 class="center-block">{{name}}</h2> | ||||
|     <div class="size"> | ||||
|         <input type="text" name="maxSize" class="knob x-knob" /> | ||||
|     </div> | ||||
|     <div class="size-value">30 minute limit: <span name="thirtyMinuteSize" class="thirty-minute-size"></span>MB</div> | ||||
|     <div class="size-value">60 minute limit: <span name="sixtyMinuteSize" class="sixty-minute-size"></span>MB</div> | ||||
| </div> | ||||
| 30 minute size: <span name="thirtyMinuteSize" class="thirty-minute-size"></span>MB | 60 minute size: <span name="sixtyMinuteSize" class="sixty-minute-size"></span>MB | ||||
| @@ -1,19 +1,19 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| define(['marionette', 'bootstrap.slider'], function (Marionette) { | ||||
| define(['marionette', 'Mixins/AsModelBoundView', 'jquery.knob'], function (Marionette, AsModelBoundView) { | ||||
|  | ||||
|     return Marionette.ItemView.extend({ | ||||
|     var view = Marionette.ItemView.extend({ | ||||
|         template : 'Settings/Quality/Size/QualitySizeTemplate', | ||||
|         className: 'quality-size-item', | ||||
|         tagName  : 'li', | ||||
|  | ||||
|         ui: { | ||||
|             slider          : '.slider', | ||||
|             knob            : '.x-knob', | ||||
|             thirtyMinuteSize: '.thirty-minute-size', | ||||
|             sixtyMinuteSize : '.sixty-minute-size' | ||||
|         }, | ||||
|  | ||||
|         events: { | ||||
|             'slide .slider': 'slide' | ||||
|             'change .x-knob': '_changeMaxSize' | ||||
|         }, | ||||
|  | ||||
|         initialize: function (options) { | ||||
| @@ -21,23 +21,25 @@ define(['marionette', 'bootstrap.slider'], function (Marionette) { | ||||
|         }, | ||||
|  | ||||
|         onRender: function () { | ||||
|             var self = this; | ||||
|             this.ui.slider.slider({ | ||||
|                 min    : 0, | ||||
|                 max    : 200, | ||||
|                 step   : 1, | ||||
|                 value  : self.model.get('maxSize'), | ||||
|                 tooltip: 'hide' | ||||
|             this.ui.knob.knob({ | ||||
|                 min         : 0, | ||||
|                 max         : 200, | ||||
|                 step        : 10, | ||||
|                 cursor      : 25, | ||||
|                 width       : 100, | ||||
|                 stopper     : true | ||||
|             }); | ||||
|         }, | ||||
|  | ||||
|         slide: function (e) { | ||||
|             var newSize = e.value; | ||||
|         _changeMaxSize: function (e, value) { | ||||
|             this.model.set({ | ||||
|                 maxSize: value | ||||
|             }); | ||||
|  | ||||
|             this.model.set({ maxSize: newSize, thirtyMinuteSize: newSize * 30, sixtyMinuteSize: newSize * 60 }); | ||||
|  | ||||
|             this.ui.thirtyMinuteSize.html(newSize * 30); | ||||
|             this.ui.sixtyMinuteSize.html(newSize * 60); | ||||
|             this.ui.thirtyMinuteSize.html(value * 30); | ||||
|             this.ui.sixtyMinuteSize.html(value * 60); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     return AsModelBoundView.call(view); | ||||
| }); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| @import "../../Shared/Styles/card"; | ||||
|  | ||||
| .quality-profiles { | ||||
| .quality-profiles, .quality-sizes { | ||||
|   li { | ||||
|     display: inline-block; | ||||
|     vertical-align: top; | ||||
| @@ -24,3 +24,35 @@ | ||||
|     margin-top: 10px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .quality-size-item { | ||||
|  | ||||
|   .card; | ||||
|  | ||||
|   width: 200px; | ||||
|   height: 200px; | ||||
|   padding: 10px 15px; | ||||
|  | ||||
|   h2 { | ||||
|     margin-top: 0px; | ||||
|     text-align: center; | ||||
|   } | ||||
|  | ||||
|   .size { | ||||
|     height: 100px; | ||||
|     margin: 10px; | ||||
|     text-align: center; | ||||
|   } | ||||
|  | ||||
|   .knob { | ||||
|     box-shadow: none; | ||||
|   } | ||||
|  | ||||
|   .size-value { | ||||
|     text-align: center; | ||||
|   } | ||||
| } | ||||
|  | ||||
| #quality-size { | ||||
|   overflow: hidden; | ||||
| } | ||||
							
								
								
									
										15
									
								
								UI/app.js
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								UI/app.js
									
									
									
									
									
								
							| @@ -8,7 +8,6 @@ require.config({ | ||||
|         'sugar'               : 'JsLibraries/sugar', | ||||
|         'handlebars'          : 'JsLibraries/handlebars.runtime', | ||||
|         'bootstrap'           : 'JsLibraries/bootstrap', | ||||
|         'bootstrap.slider'    : 'JsLibraries/bootstrap.slider', | ||||
|         'backbone.mutators'   : 'JsLibraries/backbone.mutators', | ||||
|         'backbone.deepmodel'  : 'JsLibraries/backbone.deep.model', | ||||
|         'backbone.pageable'   : 'JsLibraries/backbone.pageable', | ||||
| @@ -21,6 +20,7 @@ require.config({ | ||||
|         'underscore'          : 'JsLibraries/lodash.underscore', | ||||
|         'marionette'          : 'JsLibraries/backbone.marionette', | ||||
|         'signalR'             : 'JsLibraries/jquery.signalR', | ||||
|         'jquery.knob'         : 'JsLibraries/jquery.knob', | ||||
|         'libs'                : 'JsLibraries/' | ||||
|  | ||||
|     }, | ||||
| @@ -57,13 +57,6 @@ require.config({ | ||||
|                 ] | ||||
|         }, | ||||
|  | ||||
|         'bootstrap.slider': { | ||||
|             deps: | ||||
|                 [ | ||||
|                     '$' | ||||
|                 ] | ||||
|         }, | ||||
|  | ||||
|         backstrech: { | ||||
|             deps: | ||||
|                 [ | ||||
| @@ -116,7 +109,13 @@ require.config({ | ||||
|             } | ||||
|         }, | ||||
|  | ||||
|             deps: | ||||
|                 [ | ||||
|                     '$' | ||||
|                 ] | ||||
|         }, | ||||
|  | ||||
|         'jquery.knob': { | ||||
|         'backbone.pageable': { | ||||
|             deps: | ||||
|                 [ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user