From 78c40aab2394aa43291b4be481fd5d312e6b7c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20V=C3=A9zina?= <5130500+morpheus65535@users.noreply.github.com> Date: Fri, 26 Jun 2020 11:28:49 -0400 Subject: [PATCH] WIP --- bazarr/api.py | 18 +- static/js/jquery.slimscroll.js | 475 ++++++++++++++++++++++++++++++- static/js/settings_validation.js | 174 ----------- static/js/wizard_validation.js | 156 ---------- views/_main.html | 9 + views/settingsradarr.html | 66 ++++- views/settingssonarr.html | 83 ++++-- 7 files changed, 616 insertions(+), 365 deletions(-) delete mode 100644 static/js/settings_validation.js delete mode 100644 static/js/wizard_validation.js diff --git a/bazarr/api.py b/bazarr/api.py index 04089efcf..c516b2b46 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -1440,34 +1440,34 @@ class SyncSubtitles(Resource): class BrowseBazarrFS(Resource): @authenticate def get(self): - path = request.args.get('id') or '' + path = request.args.get('path') or '' data = [] result = browse_bazarr_filesystem(path) for item in result['directories']: - data.append({'id': item['name'], 'parent': result['parent'], 'children': True}) - return jsonify(data=data) + data.append({'text': item['name'], 'children': True, 'path': item['path']}) + return jsonify(data) class BrowseSonarrFS(Resource): @authenticate def get(self): - path = request.args.get('id') or '' + path = request.args.get('path') or '' data = [] result = browse_sonarr_filesystem(path) for item in result['directories']: - data.append({'id': item['name'], 'parent': result['parent'] if 'parent' in result else '#'}) - return jsonify(data=data) + data.append({'text': item['name'], 'children': True, 'path': item['path']}) + return jsonify(data) class BrowseRadarrFS(Resource): @authenticate def get(self): - path = request.args.get('id') or '' + path = request.args.get('path') or '' data = [] result = browse_radarr_filesystem(path) for item in result['directories']: - data.append({'id': item['name'], 'parent': result['parent'] if 'parent' in result else '#'}) - return jsonify(data=data) + data.append({'text': item['name'], 'children': True, 'path': item['path']}) + return jsonify(data) api.add_resource(Shutdown, '/shutdown') diff --git a/static/js/jquery.slimscroll.js b/static/js/jquery.slimscroll.js index 92d31d26e..90caed348 100644 --- a/static/js/jquery.slimscroll.js +++ b/static/js/jquery.slimscroll.js @@ -1 +1,474 @@ -!function(e){e.fn.extend({slimScroll:function(i){var o={width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},s=e.extend(o,i);return this.each(function(){function o(t){if(h){var t=t||window.event,i=0;t.wheelDelta&&(i=-t.wheelDelta/120),t.detail&&(i=t.detail/3);var o=t.target||t.srcTarget||t.srcElement;e(o).closest("."+s.wrapperClass).is(x.parent())&&r(i,!0),t.preventDefault&&!y&&t.preventDefault(),y||(t.returnValue=!1)}}function r(e,t,i){y=!1;var o=e,r=x.outerHeight()-R.outerHeight();if(t&&(o=parseInt(R.css("top"))+e*parseInt(s.wheelStep)/100*R.outerHeight(),o=Math.min(Math.max(o,0),r),o=e>0?Math.ceil(o):Math.floor(o),R.css({top:o+"px"})),v=parseInt(R.css("top"))/(x.outerHeight()-R.outerHeight()),o=v*(x[0].scrollHeight-x.outerHeight()),i){o=e;var a=o/x[0].scrollHeight*x.outerHeight();a=Math.min(Math.max(a,0),r),R.css({top:a+"px"})}x.scrollTop(o),x.trigger("slimscrolling",~~o),n(),c()}function a(e){window.addEventListener?(e.addEventListener("DOMMouseScroll",o,!1),e.addEventListener("mousewheel",o,!1)):document.attachEvent("onmousewheel",o)}function l(){f=Math.max(x.outerHeight()/x[0].scrollHeight*x.outerHeight(),m),R.css({height:f+"px"});var e=f==x.outerHeight()?"none":"block";R.css({display:e})}function n(){if(l(),clearTimeout(p),v==~~v){if(y=s.allowPageScroll,b!=v){var e=0==~~v?"top":"bottom";x.trigger("slimscroll",e)}}else y=!1;return b=v,f>=x.outerHeight()?void(y=!0):(R.stop(!0,!0).fadeIn("fast"),void(s.railVisible&&E.stop(!0,!0).fadeIn("fast")))}function c(){s.alwaysVisible||(p=setTimeout(function(){s.disableFadeOut&&h||u||d||(R.fadeOut("slow"),E.fadeOut("slow"))},1e3))}var h,u,d,p,g,f,v,b,w="
",m=30,y=!1,x=e(this);if(x.parent().hasClass(s.wrapperClass)){var C=x.scrollTop();if(R=x.closest("."+s.barClass),E=x.closest("."+s.railClass),l(),e.isPlainObject(i)){if("height"in i&&"auto"==i.height){x.parent().css("height","auto"),x.css("height","auto");var H=x.parent().parent().height();x.parent().css("height",H),x.css("height",H)}if("scrollTo"in i)C=parseInt(s.scrollTo);else if("scrollBy"in i)C+=parseInt(s.scrollBy);else if("destroy"in i)return R.remove(),E.remove(),void x.unwrap();r(C,!1,!0)}}else if(!(e.isPlainObject(i)&&"destroy"in i)){s.height="auto"==s.height?x.parent().height():s.height;var S=e(w).addClass(s.wrapperClass).css({position:"relative",overflow:"hidden",width:s.width,height:s.height});x.css({overflow:"hidden",width:s.width,height:s.height});var E=e(w).addClass(s.railClass).css({width:s.size,height:"100%",position:"absolute",top:0,display:s.alwaysVisible&&s.railVisible?"block":"none","border-radius":s.railBorderRadius,background:s.railColor,opacity:s.railOpacity,zIndex:90}),R=e(w).addClass(s.barClass).css({background:s.color,width:s.size,position:"absolute",top:0,opacity:s.opacity,display:s.alwaysVisible?"block":"none","border-radius":s.borderRadius,BorderRadius:s.borderRadius,MozBorderRadius:s.borderRadius,WebkitBorderRadius:s.borderRadius,zIndex:99}),D="right"==s.position?{right:s.distance}:{left:s.distance};E.css(D),R.css(D),x.wrap(S),x.parent().append(R),x.parent().append(E),s.railDraggable&&R.bind("mousedown",function(i){var o=e(document);return d=!0,t=parseFloat(R.css("top")),pageY=i.pageY,o.bind("mousemove.slimscroll",function(e){currTop=t+e.pageY-pageY,R.css("top",currTop),r(0,R.position().top,!1)}),o.bind("mouseup.slimscroll",function(e){d=!1,c(),o.unbind(".slimscroll")}),!1}).bind("selectstart.slimscroll",function(e){return e.stopPropagation(),e.preventDefault(),!1}),E.hover(function(){n()},function(){c()}),R.hover(function(){u=!0},function(){u=!1}),x.hover(function(){h=!0,n(),c()},function(){h=!1,c()}),x.bind("touchstart",function(e,t){e.originalEvent.touches.length&&(g=e.originalEvent.touches[0].pageY)}),x.bind("touchmove",function(e){if(y||e.originalEvent.preventDefault(),e.originalEvent.touches.length){var t=(g-e.originalEvent.touches[0].pageY)/s.touchScrollStep;r(t,!0),g=e.originalEvent.touches[0].pageY}}),l(),"bottom"===s.start?(R.css({top:x.outerHeight()-R.outerHeight()}),r(0,!0)):"top"!==s.start&&(r(e(s.start).position().top,null,!0),s.alwaysVisible||R.hide()),a(this)}}),this}}),e.fn.extend({slimscroll:e.fn.slimScroll})}(jQuery); \ No newline at end of file +/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Version: 1.3.8 + * + */ +(function($) { + + $.fn.extend({ + slimScroll: function(options) { + + var defaults = { + + // width in pixels of the visible scroll area + width : 'auto', + + // height in pixels of the visible scroll area + height : '250px', + + // width in pixels of the scrollbar and rail + size : '7px', + + // scrollbar color, accepts any hex/color value + color: '#000', + + // scrollbar position - left/right + position : 'right', + + // distance in pixels between the side edge and the scrollbar + distance : '1px', + + // default scroll position on load - top / bottom / $('selector') + start : 'top', + + // sets scrollbar opacity + opacity : .4, + + // enables always-on mode for the scrollbar + alwaysVisible : false, + + // check if we should hide the scrollbar when user is hovering over + disableFadeOut : false, + + // sets visibility of the rail + railVisible : false, + + // sets rail color + railColor : '#333', + + // sets rail opacity + railOpacity : .2, + + // whether we should use jQuery UI Draggable to enable bar dragging + railDraggable : true, + + // defautlt CSS class of the slimscroll rail + railClass : 'slimScrollRail', + + // defautlt CSS class of the slimscroll bar + barClass : 'slimScrollBar', + + // defautlt CSS class of the slimscroll wrapper + wrapperClass : 'slimScrollDiv', + + // check if mousewheel should scroll the window if we reach top/bottom + allowPageScroll : false, + + // scroll amount applied to each mouse wheel step + wheelStep : 20, + + // scroll amount applied when user is using gestures + touchScrollStep : 200, + + // sets border radius + borderRadius: '7px', + + // sets border radius of the rail + railBorderRadius : '7px' + }; + + var o = $.extend(defaults, options); + + // do it for every element that matches selector + this.each(function(){ + + var isOverPanel, isOverBar, isDragg, queueHide, touchDif, + barHeight, percentScroll, lastScroll, + divS = '
', + minBarHeight = 30, + releaseScroll = false; + + // used in event handlers and for better minification + var me = $(this); + + // ensure we are not binding it again + if (me.parent().hasClass(o.wrapperClass)) + { + // start from last bar position + var offset = me.scrollTop(); + + // find bar and rail + bar = me.siblings('.' + o.barClass); + rail = me.siblings('.' + o.railClass); + + getBarHeight(); + + // check if we should scroll existing instance + if ($.isPlainObject(options)) + { + // Pass height: auto to an existing slimscroll object to force a resize after contents have changed + if ( 'height' in options && options.height == 'auto' ) { + me.parent().css('height', 'auto'); + me.css('height', 'auto'); + var height = me.parent().parent().height(); + me.parent().css('height', height); + me.css('height', height); + } else if ('height' in options) { + var h = options.height; + me.parent().css('height', h); + me.css('height', h); + } + + if ('scrollTo' in options) + { + // jump to a static point + offset = parseInt(o.scrollTo); + } + else if ('scrollBy' in options) + { + // jump by value pixels + offset += parseInt(o.scrollBy); + } + else if ('destroy' in options) + { + // remove slimscroll elements + bar.remove(); + rail.remove(); + me.unwrap(); + return; + } + + // scroll content by the given offset + scrollContent(offset, false, true); + } + + return; + } + else if ($.isPlainObject(options)) + { + if ('destroy' in options) + { + return; + } + } + + // optionally set height to the parent's height + o.height = (o.height == 'auto') ? me.parent().height() : o.height; + + // wrap content + var wrapper = $(divS) + .addClass(o.wrapperClass) + .css({ + position: 'relative', + overflow: 'hidden', + width: o.width, + height: o.height + }); + + // update style for the div + me.css({ + overflow: 'hidden', + width: o.width, + height: o.height + }); + + // create scrollbar rail + var rail = $(divS) + .addClass(o.railClass) + .css({ + width: o.size, + height: '100%', + position: 'absolute', + top: 0, + display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none', + 'border-radius': o.railBorderRadius, + background: o.railColor, + opacity: o.railOpacity, + zIndex: 90 + }); + + // create scrollbar + var bar = $(divS) + .addClass(o.barClass) + .css({ + background: o.color, + width: o.size, + position: 'absolute', + top: 0, + opacity: o.opacity, + display: o.alwaysVisible ? 'block' : 'none', + 'border-radius' : o.borderRadius, + BorderRadius: o.borderRadius, + MozBorderRadius: o.borderRadius, + WebkitBorderRadius: o.borderRadius, + zIndex: 99 + }); + + // set position + var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance }; + rail.css(posCss); + bar.css(posCss); + + // wrap it + me.wrap(wrapper); + + // append to parent div + me.parent().append(bar); + me.parent().append(rail); + + // make it draggable and no longer dependent on the jqueryUI + if (o.railDraggable){ + bar.bind("mousedown", function(e) { + var $doc = $(document); + isDragg = true; + t = parseFloat(bar.css('top')); + pageY = e.pageY; + + $doc.bind("mousemove.slimscroll", function(e){ + currTop = t + e.pageY - pageY; + bar.css('top', currTop); + scrollContent(0, bar.position().top, false);// scroll content + }); + + $doc.bind("mouseup.slimscroll", function(e) { + isDragg = false;hideBar(); + $doc.unbind('.slimscroll'); + }); + return false; + }).bind("selectstart.slimscroll", function(e){ + e.stopPropagation(); + e.preventDefault(); + return false; + }); + } + + // on rail over + rail.hover(function(){ + showBar(); + }, function(){ + hideBar(); + }); + + // on bar over + bar.hover(function(){ + isOverBar = true; + }, function(){ + isOverBar = false; + }); + + // show on parent mouseover + me.hover(function(){ + isOverPanel = true; + showBar(); + hideBar(); + }, function(){ + isOverPanel = false; + hideBar(); + }); + + // support for mobile + me.bind('touchstart', function(e,b){ + if (e.originalEvent.touches.length) + { + // record where touch started + touchDif = e.originalEvent.touches[0].pageY; + } + }); + + me.bind('touchmove', function(e){ + // prevent scrolling the page if necessary + if(!releaseScroll) + { + e.originalEvent.preventDefault(); + } + if (e.originalEvent.touches.length) + { + // see how far user swiped + var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep; + // scroll content + scrollContent(diff, true); + touchDif = e.originalEvent.touches[0].pageY; + } + }); + + // set up initial height + getBarHeight(); + + // check start position + if (o.start === 'bottom') + { + // scroll content to bottom + bar.css({ top: me.outerHeight() - bar.outerHeight() }); + scrollContent(0, true); + } + else if (o.start !== 'top') + { + // assume jQuery selector + scrollContent($(o.start).position().top, null, true); + + // make sure bar stays hidden + if (!o.alwaysVisible) { bar.hide(); } + } + + // attach scroll events + attachWheel(this); + + function _onWheel(e) + { + // use mouse wheel only when mouse is over + if (!isOverPanel) { return; } + + var e = e || window.event; + + var delta = 0; + if (e.wheelDelta) { delta = -e.wheelDelta/120; } + if (e.detail) { delta = e.detail / 3; } + + var target = e.target || e.srcTarget || e.srcElement; + if ($(target).closest('.' + o.wrapperClass).is(me.parent())) { + // scroll content + scrollContent(delta, true); + } + + // stop window scroll + if (e.preventDefault && !releaseScroll) { e.preventDefault(); } + if (!releaseScroll) { e.returnValue = false; } + } + + function scrollContent(y, isWheel, isJump) + { + releaseScroll = false; + var delta = y; + var maxTop = me.outerHeight() - bar.outerHeight(); + + if (isWheel) + { + // move bar with mouse wheel + delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight(); + + // move bar, make sure it doesn't go out + delta = Math.min(Math.max(delta, 0), maxTop); + + // if scrolling down, make sure a fractional change to the + // scroll position isn't rounded away when the scrollbar's CSS is set + // this flooring of delta would happened automatically when + // bar.css is set below, but we floor here for clarity + delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta); + + // scroll the scrollbar + bar.css({ top: delta + 'px' }); + } + + // calculate actual scroll amount + percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight()); + delta = percentScroll * (me[0].scrollHeight - me.outerHeight()); + + if (isJump) + { + delta = y; + var offsetTop = delta / me[0].scrollHeight * me.outerHeight(); + offsetTop = Math.min(Math.max(offsetTop, 0), maxTop); + bar.css({ top: offsetTop + 'px' }); + } + + // scroll content + me.scrollTop(delta); + + // fire scrolling event + me.trigger('slimscrolling', ~~delta); + + // ensure bar is visible + showBar(); + + // trigger hide when scroll is stopped + hideBar(); + } + + function attachWheel(target) + { + if (window.addEventListener) + { + target.addEventListener('DOMMouseScroll', _onWheel, false ); + target.addEventListener('mousewheel', _onWheel, false ); + } + else + { + document.attachEvent("onmousewheel", _onWheel) + } + } + + function getBarHeight() + { + // calculate scrollbar height and make sure it is not too small + barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight); + bar.css({ height: barHeight + 'px' }); + + // hide scrollbar if content is not long enough + var display = barHeight == me.outerHeight() ? 'none' : 'block'; + bar.css({ display: display }); + } + + function showBar() + { + // recalculate bar height + getBarHeight(); + clearTimeout(queueHide); + + // when bar reached top or bottom + if (percentScroll == ~~percentScroll) + { + //release wheel + releaseScroll = o.allowPageScroll; + + // publish approporiate event + if (lastScroll != percentScroll) + { + var msg = (~~percentScroll == 0) ? 'top' : 'bottom'; + me.trigger('slimscroll', msg); + } + } + else + { + releaseScroll = false; + } + lastScroll = percentScroll; + + // show only when required + if(barHeight >= me.outerHeight()) { + //allow window scroll + releaseScroll = true; + return; + } + bar.stop(true,true).fadeIn('fast'); + if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); } + } + + function hideBar() + { + // only hide when options allow it + if (!o.alwaysVisible) + { + queueHide = setTimeout(function(){ + if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg) + { + bar.fadeOut('slow'); + rail.fadeOut('slow'); + } + }, 1000); + } + } + + }); + + // maintain chainability + return this; + } + }); + + $.fn.extend({ + slimscroll: $.fn.slimScroll + }); + +})(jQuery); diff --git a/static/js/settings_validation.js b/static/js/settings_validation.js deleted file mode 100644 index 50362ba3e..000000000 --- a/static/js/settings_validation.js +++ /dev/null @@ -1,174 +0,0 @@ -$('#settings_form') - .form({ - fields: { - settings_general_ip : { - rules : [ - { - type : 'regExp[/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/]', - prompt : '"General / Start-Up / Listening IP address" must be a valid IPv4 address' - }, - { - type : 'empty', - prompt : '"General / Start-Up / Listening IP address" must have a value' - } - ] - }, - settings_general_port : { - rules : [ - { - type : 'integer[1..65535]', - prompt : '"General / Start-Up / Listening port" must be an integer between 1 and 65535' - }, - { - type : 'empty', - prompt : '"General / Start-Up / Listening port" must have a value' - } - ] - }, - settings_general_chmod: { - rules: [ - { - type: 'regExp[^([0-7]{4})$]', - prompt : '"General / Start-Up / Set subtitle file permissions to" must be a 4-digit octal (e.g.: 0775)' - } - ] - }, - settings_auth_password : { - depends: 'settings_auth_username', - rules : [ - { - type : 'empty', - prompt : '"General / Security settings / Password" must have a value and you must type it again if you change your username.' - } - ] - }, - sonarr_validated_checkbox : { - depends: 'settings_general_use_sonarr', - rules : [ - { - type : 'checked', - prompt : '"Sonarr / Connection settings / Test" must be successful before going further' - } - ] - }, - settings_sonarr_ip : { - depends: 'settings_general_use_sonarr', - rules : [ - { - type : 'empty', - prompt : '"Sonarr / Connection settings / Hostname or IP address" must have a value' - } - ] - }, - settings_sonarr_port : { - depends: 'settings_general_use_sonarr', - rules : [ - { - type : 'integer[1..65535]', - prompt : '"Sonarr / Connection settings / Listening port" must be an integer between 1 and 65535' - }, - { - type : 'empty', - prompt : '"Sonarr / Connection settings / Listening port" must have a value' - } - ] - }, -// settings_sonarr_apikey : { -// depends: 'settings_general_use_sonarr', -// rules : [ -// { -// type : 'exactLength[32]', -// prompt : '"Sonarr / Connection settings / API key" must be exactly {ruleValue} characters' -// }, -// { -// type : 'empty', -// prompt : '"Sonarr / Connection settings / API key" must have a value' -// } -// ] -// }, - radarr_validated_checkbox : { - depends: 'settings_general_use_radarr', - rules : [ - { - type : 'checked', - prompt : '"Radarr / Connection settings / Test" must be successful before going further' - } - ] - }, - settings_radarr_ip : { - depends: 'settings_general_use_radarr', - rules : [ - { - type : 'empty', - prompt : '"Radarr / Connection settings / Hostname or IP address" must have a value' - } - ] - }, - settings_radarr_port : { - depends: 'settings_general_use_radarr', - rules : [ - { - type : 'integer[1..65535]', - prompt : '"Radarr / Connection settings / Listening port" must be an integer between 1 and 65535' - }, - { - type : 'empty', - prompt : '"Radarr / Connection settings / Listening port" must have a value' - } - ] - }, -// settings_radarr_apikey : { -// depends: 'settings_general_use_radarr', -// rules : [ -// { -// type : 'exactLength[32]', -// prompt : '"Radarr / Connection settings / API key" must be exactly {ruleValue} characters' -// }, -// { -// type : 'empty', -// prompt : '"Radarr / Connection settings / API key" must have a value' -// } -// ] -// }, - settings_subliminal_providers : { - rules : [ - { - type : 'minCount[1]', - prompt : '"Subtitles / Subtitles providers" must have at least one enabled provider' - } - ] - }, - settings_subliminal_languages : { - rules : [ - { - type : 'minCount[1]', - prompt : '"Subtitles / Subtitles languages / Enabled languages" must have at least one enabled language' - } - ] - }, - settings_days_to_upgrade_subs : { - depends: 'settings_upgrade_subs', - rules : [ - { - type : 'integer[1..30]', - prompt : '"Subtitles / Subtitles options / Number of days to go back in history..." must be an integer between 1 and 30' - } - ] - } - }, - inline : false, - selector : { - message: '#form_validation_error' - }, - on : 'change', - onFailure: function(){ - $('.submit').addClass('disabled'); - return false; - }, - onSuccess: function(){ - $('.submit').removeClass('disabled'); - $('#loader').addClass('active'); - } - }) -; - diff --git a/static/js/wizard_validation.js b/static/js/wizard_validation.js deleted file mode 100644 index 2a5312757..000000000 --- a/static/js/wizard_validation.js +++ /dev/null @@ -1,156 +0,0 @@ -$('#wizard_form') - .form({ - fields: { - settings_general_ip : { - rules : [ - { - type : 'regExp[/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/]', - prompt : '"General / Start-Up / Listening IP address" must be a valid IPv4 address' - }, - { - type : 'empty', - prompt : '"General / Start-Up / Listening IP address" must have a value' - } - ] - }, - settings_general_port : { - rules : [ - { - type : 'integer[1..65535]', - prompt : '"General / Start-Up / Listening port" must be an integer between 1 and 65535' - }, - { - type : 'empty', - prompt : '"General / Start-Up / Listening port" must have a value' - } - ] - }, - sonarr_validated_checkbox : { - depends: 'settings_general_use_sonarr', - rules : [ - { - type : 'checked', - prompt : '"Sonarr / Connection settings / Test" must be successful before going further' - } - ] - }, - settings_sonarr_ip : { - depends: 'settings_general_use_sonarr', - rules : [ - { - type : 'empty', - prompt : '"Sonarr / Connection settings / Hostname or IP address" must have a value' - } - ] - }, - settings_sonarr_port : { - depends: 'settings_general_use_sonarr', - rules : [ - { - type : 'integer[1..65535]', - prompt : '"Sonarr / Connection settings / Listening port" must be an integer between 1 and 65535' - }, - { - type : 'empty', - prompt : '"Sonarr / Connection settings / Listening port" must have a value' - } - ] - }, -// settings_sonarr_apikey : { -// depends: 'settings_general_use_sonarr', -// rules : [ -// { -// type : 'exactLength[32]', -// prompt : '"Sonarr / Connection settings / API key" must be exactly {ruleValue} characters' -// }, -// { -// type : 'empty', -// prompt : '"Sonarr / Connection settings / API key" must have a value' -// } -// ] -// }, - radarr_validated_checkbox : { - depends: 'settings_general_use_radarr', - rules : [ - { - type : 'checked', - prompt : '"Radarr / Connection settings / Test" must be successful before going further' - } - ] - }, - settings_radarr_ip : { - depends: 'settings_general_use_radarr', - rules : [ - { - type : 'empty', - prompt : '"Radarr / Connection settings / Hostname or IP address" must have a value' - } - ] - }, - settings_radarr_port : { - depends: 'settings_general_use_radarr', - rules : [ - { - type : 'integer[1..65535]', - prompt : '"Radarr / Connection settings / Listening port" must be an integer between 1 and 65535' - }, - { - type : 'empty', - prompt : '"Radarr / Connection settings / Listening port" must have a value' - } - ] - }, -// settings_radarr_apikey : { -// depends: 'settings_general_use_radarr', -// rules : [ -// { -// type : 'exactLength[32]', -// prompt : '"Radarr / Connection settings / API key" must be exactly {ruleValue} characters' -// }, -// { -// type : 'empty', -// prompt : '"Radarr / Connection settings / API key" must have a value' -// } -// ] -// }, - settings_subliminal_providers : { - rules : [ - { - type : 'minCount[1]', - prompt : '"Subtitles / Subtitles providers" must have at least one enabled provider' - } - ] - }, - settings_subliminal_languages : { - rules : [ - { - type : 'minCount[1]', - prompt : '"Subtitles / Subtitles languages / Enabled languages" must have at least one enabled language' - } - ] - } - }, - inline : false, - selector : { - message: '#form_validation_error' - }, - on : 'change', - onFailure: function(){ - $('#submit').addClass('disabled'); - $('.prev2').addClass('disabled'); - $('.prev3').addClass('disabled'); - $('.next2').addClass('disabled'); - $('.next3').addClass('disabled'); - - - return false; - }, - onSuccess: function(){ - $('#submit').removeClass('disabled'); - $('.prev2').removeClass('disabled'); - $('.prev3').removeClass('disabled'); - $('.next2').removeClass('disabled'); - $('.next3').removeClass('disabled'); - } - }) -; \ No newline at end of file diff --git a/views/_main.html b/views/_main.html index 1ae6856d2..9edff80d4 100644 --- a/views/_main.html +++ b/views/_main.html @@ -77,6 +77,15 @@ .slider_span { margin-left: 1em; } + + .filetree { + border: 1px solid #ced4da; + border-radius: .25rem; + } + + #add_path_sonarr, #add_path_radarr, #add_path_bazarr { + margin-bottom: 0.5em; + } {% endblock head %} diff --git a/views/settingsradarr.html b/views/settingsradarr.html index fc64adc08..260915e52 100644 --- a/views/settingsradarr.html +++ b/views/settingsradarr.html @@ -141,6 +141,12 @@

Path Mappings


+
Some tips to ensure things goes smoothly:
+
@@ -170,7 +176,8 @@ Path for Radarr
- + +

@@ -179,7 +186,8 @@ Path for Bazarr
- + +
@@ -364,11 +372,61 @@ }] }); + $('#addModal').on('hidden.bs.modal', function() { + $('#add_form')[0].reset(); + $('#radarr_browser').jstree('destroy'); + $('#radarr_browser').slimScroll({destroy: true}); + $('#bazarr_browser').jstree('destroy'); + $('#bazarr_browser').slimScroll({destroy: true}); + }) + + $('#addModal').on('show.bs.modal', function() { + $('#radarr_browser').slimScroll({ + height: '200px', + start: 'top' + }); + $('#radarr_browser').jstree({ + 'core' : { + 'data' : { + 'url' : '{{ url_for('api.browseradarrfs') }}', + 'data' : function (node) { + if (node.original === undefined) { + return {'path': ''}; + } else { + return {'path': node.original.path}; + } + } + } + } + }).on('changed.jstree', function (e, data) { + $('#add_path_radarr').val(data.node.original.path); + }); + + $('#bazarr_browser').slimScroll({ + height: '200px', + start: 'top' + }); + $('#bazarr_browser').jstree({ + 'core' : { + 'data' : { + 'url' : '{{ url_for('api.browsebazarrfs') }}', + 'data' : function (node) { + if (node.original === undefined) { + return {'path': ''}; + } else { + return {'path': node.original.path}; + } + } + } + } + }).on('changed.jstree', function (e, data) { + $('#add_path_bazarr').val(data.node.original.path); + }); + }) + $('#add_save_button').on('click', function(e) { e.preventDefault(); table.row.add([ $('#add_path_radarr').val(), $('#add_path_bazarr').val()]).draw(); - $('#add_path_radarr').val(''); - $('#add_path_bazarr').val(''); $('#addModal').modal('hide'); $('#settings_form').trigger('change'); }); diff --git a/views/settingssonarr.html b/views/settingssonarr.html index 6f8e8cdd1..b0f88a00d 100644 --- a/views/settingssonarr.html +++ b/views/settingssonarr.html @@ -141,6 +141,12 @@

Path Mappings


+
Some tips to ensure things goes smoothly:
+
@@ -170,8 +176,8 @@ Path for Sonarr
- -
+ +

@@ -180,8 +186,8 @@ Path for Bazarr
- -
+ +
@@ -366,11 +372,61 @@ }] }); + $('#addModal').on('hidden.bs.modal', function() { + $('#add_form')[0].reset(); + $('#sonarr_browser').jstree('destroy'); + $('#sonarr_browser').slimScroll({destroy: true}); + $('#bazarr_browser').jstree('destroy'); + $('#bazarr_browser').slimScroll({destroy: true}); + }) + + $('#addModal').on('show.bs.modal', function() { + $('#sonarr_browser').slimScroll({ + height: '200px', + start: 'top' + }); + $('#sonarr_browser').jstree({ + 'core' : { + 'data' : { + 'url' : '{{ url_for('api.browsesonarrfs') }}', + 'data' : function (node) { + if (node.original === undefined) { + return {'path': ''}; + } else { + return {'path': node.original.path}; + } + } + } + } + }).on('changed.jstree', function (e, data) { + $('#add_path_sonarr').val(data.node.original.path); + }); + + $('#bazarr_browser').slimScroll({ + height: '200px', + start: 'top' + }); + $('#bazarr_browser').jstree({ + 'core' : { + 'data' : { + 'url' : '{{ url_for('api.browsebazarrfs') }}', + 'data' : function (node) { + if (node.original === undefined) { + return {'path': ''}; + } else { + return {'path': node.original.path}; + } + } + } + } + }).on('changed.jstree', function (e, data) { + $('#add_path_bazarr').val(data.node.original.path); + }); + }) + $('#add_save_button').on('click', function(e) { e.preventDefault(); table.row.add([ $('#add_path_sonarr').val(), $('#add_path_bazarr').val()]).draw(); - $('#add_path_sonarr').val(''); - $('#add_path_bazarr').val(''); $('#addModal').modal('hide'); $('#settings_form').trigger('change'); }); @@ -413,21 +469,6 @@ form_changed = true; $('#save_button').prop('disabled', false).css('cursor', 'auto'); }) - - $('#sonarr_browser').jstree({ - 'core' : { - 'data' : { - 'url' : '{{ url_for('api.browsesonarrfs') }}' - } - } - }); - $('#bazarr_browser').jstree({ - 'core' : { - 'data' : { - 'url' : '{{ url_for('api.browsebazarrfs') }}' - } - } - }); }); {% endblock tail %}