diff --git a/web/app.js b/web/app.js index 1a500b7..5bb4cd8 100644 --- a/web/app.js +++ b/web/app.js @@ -2,8 +2,9 @@ const angular = require('angular') require('angular-router-browserify')(angular) require('./ext/lazyload')(angular) require('./ext/dragdrop') +require('./ext/angularjs-scroll-glue') -var app = angular.module('myApp', ['ngRoute', 'angularLazyImg', 'dndLists']) +var app = angular.module('myApp', ['ngRoute', 'angularLazyImg', 'dndLists', 'luegg.directives']) app.service('plex', require('./services/plex')) app.service('pseudotv', require('./services/pseudotv')) diff --git a/web/directives/channel-config.js b/web/directives/channel-config.js index 47d5a8d..27cb3d6 100644 --- a/web/directives/channel-config.js +++ b/web/directives/channel-config.js @@ -141,12 +141,11 @@ module.exports = function ($timeout) { index = 0 } } - scope.channel.programs = newProgs.concat(movies) updateChannelDuration() } scope.randomShuffle = () => { - randomShuffle(scope.channel.programs) + shuffle(scope.channel.programs) updateChannelDuration() } function getRandomInt(min, max) { @@ -154,12 +153,16 @@ module.exports = function ($timeout) { max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } - function randomShuffle(a) { - for (let i = a.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)) - [a[i], a[j]] = [a[j], a[i]] + function shuffle(array) { + var currentIndex = array.length, temporaryValue, randomIndex + while (0 !== currentIndex) { + randomIndex = Math.floor(Math.random() * currentIndex) + currentIndex -= 1 + temporaryValue = array[currentIndex] + array[currentIndex] = array[randomIndex] + array[randomIndex] = temporaryValue } - return a + return array } function updateChannelDuration() { scope.channel.duration = 0 diff --git a/web/ext/angularjs-scroll-glue.js b/web/ext/angularjs-scroll-glue.js new file mode 100644 index 0000000..70abaa1 --- /dev/null +++ b/web/ext/angularjs-scroll-glue.js @@ -0,0 +1,164 @@ +/* angularjs Scroll Glue + * version 2.1.0 + * https://github.com/Luegg/angularjs-scroll-glue + * An AngularJs directive that automatically scrolls to the bottom of an element on changes in it's scope. +*/ + +// Allow module to be loaded via require when using common js. e.g. npm +if(typeof module === "object" && module.exports){ + module.exports = 'luegg.directives'; +} + +(function(angular, undefined){ + 'use strict'; + + function createActivationState($parse, attr, scope){ + function unboundState(initValue){ + var activated = initValue; + return { + getValue: function(){ + return activated; + }, + setValue: function(value){ + activated = value; + } + }; + } + + function oneWayBindingState(getter, scope){ + return { + getValue: function(){ + return getter(scope); + }, + setValue: function(){} + }; + } + + function twoWayBindingState(getter, setter, scope){ + return { + getValue: function(){ + return getter(scope); + }, + setValue: function(value){ + if(value !== getter(scope)){ + scope.$apply(function(){ + setter(scope, value); + }); + } + } + }; + } + + if(attr !== ""){ + var getter = $parse(attr); + if(getter.assign !== undefined){ + return twoWayBindingState(getter, getter.assign, scope); + } else { + return oneWayBindingState(getter, scope); + } + } else { + return unboundState(true); + } + } + + function createDirective(module, attrName, direction){ + module.directive(attrName, ['$parse', '$window', '$timeout', function($parse, $window, $timeout){ + return { + priority: 1, + restrict: 'A', + link: function(scope, $el, attrs){ + var el = $el[0], + activationState = createActivationState($parse, attrs[attrName], scope); + + function scrollIfGlued() { + if(activationState.getValue() && !direction.isAttached(el)){ + // Ensures scroll after angular template digest + $timeout(function() { + direction.scroll(el); + }); + } + } + + function onScroll() { + activationState.setValue(direction.isAttached(el)); + } + + $timeout(scrollIfGlued, 0, false); + + if (!$el[0].hasAttribute('force-glue')) { + $el.on('scroll', onScroll); + } + + var hasAnchor = false; + angular.forEach($el.children(), function(child) { + if (child.hasAttribute('scroll-glue-anchor')) { + hasAnchor = true; + scope.$watch(function() { return child.offsetHeight }, function() { + scrollIfGlued(); + }); + } + }); + + if (!hasAnchor) { + scope.$watch(scrollIfGlued); + $window.addEventListener('resize', scrollIfGlued, false); + } + + // Remove listeners on directive destroy + $el.on('$destroy', function() { + $el.unbind('scroll', onScroll); + }); + + scope.$on('$destroy', function() { + $window.removeEventListener('resize', scrollIfGlued, false); + }); + } + }; + }]); + } + + var bottom = { + isAttached: function(el){ + // + 1 catches off by one errors in chrome + return el.scrollTop + el.clientHeight + 1 >= el.scrollHeight; + }, + scroll: function(el){ + el.scrollTop = el.scrollHeight; + } + }; + + var top = { + isAttached: function(el){ + return el.scrollTop <= 1; + }, + scroll: function(el){ + el.scrollTop = 0; + } + }; + + var right = { + isAttached: function(el){ + return el.scrollLeft + el.clientWidth + 1 >= el.scrollWidth; + }, + scroll: function(el){ + el.scrollLeft = el.scrollWidth; + } + }; + + var left = { + isAttached: function(el){ + return el.scrollLeft <= 1; + }, + scroll: function(el){ + el.scrollLeft = 0; + } + }; + + var module = angular.module('luegg.directives', []); + + createDirective(module, 'scrollGlue', bottom); + createDirective(module, 'scrollGlueTop', top); + createDirective(module, 'scrollGlueBottom', bottom); + createDirective(module, 'scrollGlueLeft', left); + createDirective(module, 'scrollGlueRight', right); +}(angular)); \ No newline at end of file diff --git a/web/public/templates/channel-config.html b/web/public/templates/channel-config.html index 2f7b8ee..e0493e1 100644 --- a/web/public/templates/channel-config.html +++ b/web/public/templates/channel-config.html @@ -37,6 +37,7 @@