From 7c4adb148046b60a623097799327777a649700c0 Mon Sep 17 00:00:00 2001 From: Martin Gruber Date: Fri, 15 May 2015 13:23:47 +0200 Subject: [PATCH] FIXED: Scrolling functionality when element size is provided. --- src/angular-vs-repeat.js | 42 +++++++++++++++++++++++++----------- src/angular-vs-repeat.min.js | 2 +- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/angular-vs-repeat.js b/src/angular-vs-repeat.js index 7a78105..de7c659 100644 --- a/src/angular-vs-repeat.js +++ b/src/angular-vs-repeat.js @@ -413,8 +413,10 @@ var scrollChange = true, position, - visibleStartIndex; - + visibleStartIndex, + scrollIndexCumulativeSize, + scrollIndexSize; + if (data && data.elementSize !== undefined) $scope.elementSize = data.elementSize; if (data && data.scrollIndex !== undefined) { @@ -422,6 +424,15 @@ $scope.scrollSettings.scrollIndex = data.scrollIndex; } + if (sizesPropertyExists) { + scrollIndexSize = $scope.sizes[data.scrollIndex]; + scrollIndexCumulativeSize = $scope.sizesCumulative[data.scrollIndex]; + } + else { + scrollIndexSize = $scope.elementSize; + scrollIndexCumulativeSize = data.scrollIndex * $scope.elementSize; + } + // Item scroll position relative to the view, i.e. position === 0 means the top of the view, // position === $scrollParent[0][clientSize] means the bottom if (data.scrollIndexPosition !== undefined) { @@ -439,10 +450,10 @@ position = $scope.offsetBefore; break; case 'middle': - position = ($scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex]) / 2; + position = ($scrollParent[0][clientSize] - scrollIndexSize) / 2; break; case 'bottom': - position = $scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex] - $scope.offsetAfter; + position = $scrollParent[0][clientSize] - scrollIndexSize - $scope.offsetAfter; break; case 'inview': case 'inview#top': @@ -451,11 +462,11 @@ case 'inview#auto': // The item is in the viewport, do nothing if ( - ($scrollParent[0][scrollPos] <= ($scope.sizesCumulative[data.scrollIndex])) && - ($scrollParent[0][scrollPos] + $scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex] >= $scope.sizesCumulative[data.scrollIndex])) { + ($scrollParent[0][scrollPos] <= (scrollIndexCumulativeSize)) && + ($scrollParent[0][scrollPos] + $scrollParent[0][clientSize] - scrollIndexSize >= scrollIndexCumulativeSize)) { scrollChange = false; // The current item scroll position - position = $scope.sizesCumulative[data.scrollIndex] - $scrollParent[0][scrollPos]; + position = scrollIndexCumulativeSize - $scrollParent[0][scrollPos]; } // The item is out of the viewport else { @@ -465,16 +476,16 @@ } if (data.scrollIndexPosition === 'inview#bottom') { // Get it at the bottom - position = $scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex] + $scope.offsetAfter; + position = $scrollParent[0][clientSize] - scrollIndexSize + $scope.offsetAfter; } if (data.scrollIndexPosition === 'inview#middle') { // Get it at the middle - position = ($scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex]) / 2; + position = ($scrollParent[0][clientSize] - scrollIndexSize) / 2; } if (data.scrollIndexPosition === 'inview#auto') { // Get it at the bottom or at the top, depending on what is closer - if ($scrollParent[0][scrollPos] <= $scope.sizesCumulative[data.scrollIndex]) { - position = $scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex] + $scope.offsetAfter; + if ($scrollParent[0][scrollPos] <= scrollIndexCumulativeSize) { + position = $scrollParent[0][clientSize] - scrollIndexSize + $scope.offsetAfter; } else { position = $scope.offsetBefore; @@ -496,7 +507,12 @@ // The item is not required to be in the viewport, do nothing scrollChange = false; // The current item scroll position - position = $scope.sizesCumulative[data.scrollIndex] - $scrollParent[0][scrollPos]; + if (sizesPropertyExists) { + position = $scope.sizesCumulative[data.scrollIndex] - $scrollParent[0][scrollPos]; + } + else { + position = (data.scrollIndex * $scope.elementSize) - $scrollParent[0][scrollPos]; + } } $scope.startIndex = data.scrollIndex; @@ -590,7 +606,7 @@ var scrolled = false; if (data !== undefined && data.scrollIndex !== undefined && position !== undefined && scrollChange) { // Scroll to the requested position - scrolled = scrollToPosition($scope.sizesCumulative[data.scrollIndex] - position); + scrolled = scrollToPosition(scrollIndexCumulativeSize - position); } var digestRequired = $scope.startIndex !== _prevStartIndex || $scope.endIndex !== _prevEndIndex; diff --git a/src/angular-vs-repeat.min.js b/src/angular-vs-repeat.min.js index 57f7b95..d0540a3 100644 --- a/src/angular-vs-repeat.min.js +++ b/src/angular-vs-repeat.min.js @@ -1 +1 @@ -!function(a,b){"use strict";var c=-1!=navigator.appVersion.indexOf("Mac"),d="undefined"!=typeof a.onwheel?"wheel":"undefined"!=typeof a.onmousewheel?"mousewheel":"DOMMouseScroll",e=document.documentElement,f=e.matches?"matches":e.matchesSelector?"matchesSelector":e.webkitMatches?"webkitMatches":e.webkitMatchesSelector?"webkitMatchesSelector":e.msMatches?"msMatches":e.msMatchesSelector?"msMatchesSelector":e.mozMatches?"mozMatches":e.mozMatchesSelector?"mozMatchesSelector":null,g=b.element.prototype.closest||function(a){for(var c=this[0].parentNode;c!==document.documentElement&&null!=c&&!c[f](a);)c=c.parentNode;return c&&c[f](a)?b.element(c):b.element()};b.module("vs-repeat",[]).directive("vsRepeat",["$compile",function(e){return{restrict:"A",scope:!0,require:"?^vsRepeat",controller:["$scope",function(a){this.$scrollParent=a.$scrollParent,this.$fillElement=a.$fillElement}],compile:function(f){var h=f.children().eq(0),i=h.attr("ng-repeat"),j=h[0].outerHTML,k=/^\s*(\S+)\s+in\s+([\S\s]+?)(track\s+by\s+\S+)?$/.exec(i),l=k[1],m=k[2],n=k[3],o="$vs_collection",p={vsRepeat:"elementSize",vsOffsetBefore:"offsetBefore",vsOffsetAfter:"offsetAfter",vsExcess:"excess"};return f.empty(),a.getComputedStyle&&"absolute"===a.getComputedStyle(f[0]).position||f.css("position","relative"),{pre:function(f,h,i,k){function q(a,b){if(!D||D.length<1)return f[o]=[],z=0,v(0),void(f.sizesCumulative=[0]);if(z=D.length,G){f.sizes=D.map(function(a){return a[i.vsSizeProperty]});var c=0;f.sizesCumulative=f.sizes.map(function(a){var b=c;return c+=a,b}),f.sizesCumulative.push(c)}r(),u(b)}function r(){F&&f.$$postDigest(function(){if(h[0].offsetHeight||h[0].offsetWidth)for(var a=h.children(),b=0;bb.clientWidth||b.scrollHeight>b.clientHeight)&&A.css("display","block")}function t(){"undefined"!=typeof i.vsAutoresize&&(F=!0,r(),f.$root&&!f.$root.$$phase&&f.$apply()),y()&&f.$apply()}function u(a){Q=void 0,R=void 0,y(a),v(G?f.sizesCumulative[z]:f.elementSize*z),f.$emit("vsRepeatReinitialized",f.startIndex,f.endIndex)}function v(a){if(E){if(B.css({width:f.offsetBefore+a+f.offsetAfter+"px",height:"100%"}),k&&k.$fillElement){var b=k.$fillElement[0].parentNode.querySelector("[ng-repeat]");b&&k.$fillElement.css({width:b.scrollWidth+"px"})}}else B.css({height:f.offsetBefore+a+f.offsetAfter+"px",width:"100%"}),k&&k.$fillElement&&(b=k.$fillElement[0].parentNode.querySelector("[ng-repeat]"),b&&k.$fillElement.css({height:b.scrollHeight+"px"}))}function w(){var a=H[0][L];a!==S&&(u(),f.$root&&!f.$root.$$phase&&f.$apply()),S=a}function x(a){var b=!1;return void 0!==a&&"number"==typeof a&&(b=Math.max(a,0),H[0][N]!==b?(H[0][N]=b,K=!0):b=!1,f.$emit("vsRepeatScrolled",b)),b}function y(a){var b,c,d=!0;if(a&&void 0!==a.scrollIndex){if("undefined"!=typeof f.scrollSettings&&(f.scrollSettings.scrollIndex=a.scrollIndex),void 0!==a.scrollIndexPosition)switch("undefined"!=typeof f.scrollSettings&&(f.scrollSettings.scrollIndexPosition=a.scrollIndexPosition),b=0,typeof a.scrollIndexPosition){case"number":b=a.scrollIndexPosition+f.offsetBefore;break;case"string":switch(a.scrollIndexPosition){case"top":b=f.offsetBefore;break;case"middle":b=(H[0][L]-f.sizes[a.scrollIndex])/2;break;case"bottom":b=H[0][L]-f.sizes[a.scrollIndex]-f.offsetAfter;break;case"inview":case"inview#top":case"inview#middle":case"inview#bottom":case"inview#auto":H[0][N]<=f.sizesCumulative[a.scrollIndex]&&H[0][N]+H[0][L]-f.sizes[a.scrollIndex]>=f.sizesCumulative[a.scrollIndex]?(d=!1,b=f.sizesCumulative[a.scrollIndex]-H[0][N]):(("inview#top"===a.scrollIndexPosition||"inview"===a.scrollIndexPosition)&&(b=f.offsetBefore),"inview#bottom"===a.scrollIndexPosition&&(b=H[0][L]-f.sizes[a.scrollIndex]+f.offsetAfter),"inview#middle"===a.scrollIndexPosition&&(b=(H[0][L]-f.sizes[a.scrollIndex])/2),"inview#auto"===a.scrollIndexPosition&&(b=H[0][N]<=f.sizesCumulative[a.scrollIndex]?H[0][L]-f.sizes[a.scrollIndex]+f.offsetAfter:f.offsetBefore));break;default:console.warn("Incorrect scrollIndexPosition string value")}break;default:console.warn("Incorrect scrollIndexPosition type")}else d=!1,b=f.sizesCumulative[a.scrollIndex]-H[0][N];if(f.startIndex=a.scrollIndex,G){for(;f.sizesCumulative[f.startIndex]>f.sizesCumulative[a.scrollIndex]-b;)f.startIndex--;for(c=f.startIndex,f.startIndex=Math.max(Math.floor(f.startIndex-f.excess/2),0),f.endIndex=f.startIndex;f.sizesCumulative[f.endIndex]a.scrollIndex*f.elementSize-b;)f.startIndex--;c=f.startIndex,f.startIndex=Math.max(Math.floor(f.startIndex-f.excess/2),0),f.endIndex=Math.min(f.startIndex+Math.ceil(H[0][L]/f.elementSize)+f.excess/2,z)}}else if(G){for(f.startIndex=0;f.sizesCumulative[f.startIndex]0&&f.startIndex--,f.startIndex=Math.max(Math.floor(f.startIndex-f.excess/2),0),f.endIndex=f.startIndex;f.sizesCumulative[f.endIndex]').css({position:"relative","min-height":"100%","min-width":"100%"}),h.append(B),e(B)(f),f.$fillElement=B;var P={};c&&(A=b.element('
').on(d,function(a){a.preventDefault(),a.stopPropagation(),a.originalEvent&&(a=a.originalEvent),H[0].scrollLeft+=a.deltaX||-a.wheelDeltaX,H[0].scrollTop+=a.deltaY||-a.wheelDeltaY}).on("mousemove",function(a){(P.x!==a.clientX||P.y!==a.clientY)&&b.element(this).css("display","none"),P={x:a.clientX,y:a.clientY}}).css("display","none"),B.append(A)),f.startIndex=0,f.endIndex=0,H.on("scroll",function(){K?K=!1:y()&&f.$apply()}),c&&H.on(d,s),b.element(a).on("resize",t),f.$on("$destroy",function(){b.element(a).off("resize",t)}),f.$on("vsRepeatTrigger",q),f.$on("vsRepeatResize",function(){F=!0,r()});var Q,R,S;f.$watch(function(){"function"==typeof a.requestAnimationFrame?a.requestAnimationFrame(w):w()})}}}}}]),b.element(document.head).append([""].join(""))}(window,window.angular); \ No newline at end of file +!function(a,b){"use strict";var c=-1!=navigator.appVersion.indexOf("Mac"),d="undefined"!=typeof a.onwheel?"wheel":"undefined"!=typeof a.onmousewheel?"mousewheel":"DOMMouseScroll",e=document.documentElement,f=e.matches?"matches":e.matchesSelector?"matchesSelector":e.webkitMatches?"webkitMatches":e.webkitMatchesSelector?"webkitMatchesSelector":e.msMatches?"msMatches":e.msMatchesSelector?"msMatchesSelector":e.mozMatches?"mozMatches":e.mozMatchesSelector?"mozMatchesSelector":null,g=b.element.prototype.closest||function(a){for(var c=this[0].parentNode;c!==document.documentElement&&null!=c&&!c[f](a);)c=c.parentNode;return c&&c[f](a)?b.element(c):b.element()};b.module("vs-repeat",[]).directive("vsRepeat",["$compile",function(e){return{restrict:"A",scope:!0,require:"?^vsRepeat",controller:["$scope",function(a){this.$scrollParent=a.$scrollParent,this.$fillElement=a.$fillElement}],compile:function(f){var h=f.children().eq(0),i=h.attr("ng-repeat"),j=h[0].outerHTML,k=/^\s*(\S+)\s+in\s+([\S\s]+?)(track\s+by\s+\S+)?$/.exec(i),l=k[1],m=k[2],n=k[3],o="$vs_collection",p={vsRepeat:"elementSize",vsOffsetBefore:"offsetBefore",vsOffsetAfter:"offsetAfter",vsExcess:"excess"};return f.empty(),a.getComputedStyle&&"absolute"===a.getComputedStyle(f[0]).position||f.css("position","relative"),{pre:function(f,h,i,k){function q(a,b){if(!D||D.length<1)return f[o]=[],z=0,v(0),void(f.sizesCumulative=[0]);if(z=D.length,G){f.sizes=D.map(function(a){return a[i.vsSizeProperty]});var c=0;f.sizesCumulative=f.sizes.map(function(a){var b=c;return c+=a,b}),f.sizesCumulative.push(c)}r(),u(b)}function r(){F&&f.$$postDigest(function(){if(h[0].offsetHeight||h[0].offsetWidth)for(var a=h.children(),b=0;bb.clientWidth||b.scrollHeight>b.clientHeight)&&A.css("display","block")}function t(){"undefined"!=typeof i.vsAutoresize&&(F=!0,r(),f.$root&&!f.$root.$$phase&&f.$apply()),y()&&f.$apply()}function u(a){Q=void 0,R=void 0,y(a),v(G?f.sizesCumulative[z]:f.elementSize*z),f.$emit("vsRepeatReinitialized",f.startIndex,f.endIndex)}function v(a){if(E){if(B.css({width:f.offsetBefore+a+f.offsetAfter+"px",height:"100%"}),k&&k.$fillElement){var b=k.$fillElement[0].parentNode.querySelector("[ng-repeat]");b&&k.$fillElement.css({width:b.scrollWidth+"px"})}}else B.css({height:f.offsetBefore+a+f.offsetAfter+"px",width:"100%"}),k&&k.$fillElement&&(b=k.$fillElement[0].parentNode.querySelector("[ng-repeat]"),b&&k.$fillElement.css({height:b.scrollHeight+"px"}))}function w(){var a=H[0][L];a!==S&&(u(),f.$root&&!f.$root.$$phase&&f.$apply()),S=a}function x(a){var b=!1;return void 0!==a&&"number"==typeof a&&(b=Math.max(a,0),H[0][N]!==b?(H[0][N]=b,K=!0):b=!1,f.$emit("vsRepeatScrolled",b)),b}function y(a){var b,c,d,e,g=!0;if(a&&void 0!==a.elementSize&&(f.elementSize=a.elementSize),a&&void 0!==a.scrollIndex){if("undefined"!=typeof f.scrollSettings&&(f.scrollSettings.scrollIndex=a.scrollIndex),G?(e=f.sizes[a.scrollIndex],d=f.sizesCumulative[a.scrollIndex]):(e=f.elementSize,d=a.scrollIndex*f.elementSize),void 0!==a.scrollIndexPosition)switch("undefined"!=typeof f.scrollSettings&&(f.scrollSettings.scrollIndexPosition=a.scrollIndexPosition),b=0,typeof a.scrollIndexPosition){case"number":b=a.scrollIndexPosition+f.offsetBefore;break;case"string":switch(a.scrollIndexPosition){case"top":b=f.offsetBefore;break;case"middle":b=(H[0][L]-e)/2;break;case"bottom":b=H[0][L]-e-f.offsetAfter;break;case"inview":case"inview#top":case"inview#middle":case"inview#bottom":case"inview#auto":H[0][N]<=d&&H[0][N]+H[0][L]-e>=d?(g=!1,b=d-H[0][N]):(("inview#top"===a.scrollIndexPosition||"inview"===a.scrollIndexPosition)&&(b=f.offsetBefore),"inview#bottom"===a.scrollIndexPosition&&(b=H[0][L]-e+f.offsetAfter),"inview#middle"===a.scrollIndexPosition&&(b=(H[0][L]-e)/2),"inview#auto"===a.scrollIndexPosition&&(b=H[0][N]<=d?H[0][L]-e+f.offsetAfter:f.offsetBefore));break;default:console.warn("Incorrect scrollIndexPosition string value")}break;default:console.warn("Incorrect scrollIndexPosition type")}else g=!1,b=G?f.sizesCumulative[a.scrollIndex]-H[0][N]:a.scrollIndex*f.elementSize-H[0][N];if(f.startIndex=a.scrollIndex,G){for(;f.sizesCumulative[f.startIndex]>f.sizesCumulative[a.scrollIndex]-b;)f.startIndex--;for(c=f.startIndex,f.startIndex=Math.max(Math.floor(f.startIndex-f.excess/2),0),f.endIndex=f.startIndex;f.sizesCumulative[f.endIndex]a.scrollIndex*f.elementSize-b;)f.startIndex--;c=f.startIndex,f.startIndex=Math.max(Math.floor(f.startIndex-f.excess/2),0),f.endIndex=Math.min(f.startIndex+Math.ceil(H[0][L]/f.elementSize)+f.excess/2,z)}}else if(G){for(f.startIndex=0;f.sizesCumulative[f.startIndex]0&&f.startIndex--,f.startIndex=Math.max(Math.floor(f.startIndex-f.excess/2),0),f.endIndex=f.startIndex;f.sizesCumulative[f.endIndex]').css({position:"relative","min-height":"100%","min-width":"100%"}),h.append(B),e(B)(f),f.$fillElement=B;var P={};c&&(A=b.element('
').on(d,function(a){a.preventDefault(),a.stopPropagation(),a.originalEvent&&(a=a.originalEvent),H[0].scrollLeft+=a.deltaX||-a.wheelDeltaX,H[0].scrollTop+=a.deltaY||-a.wheelDeltaY}).on("mousemove",function(a){(P.x!==a.clientX||P.y!==a.clientY)&&b.element(this).css("display","none"),P={x:a.clientX,y:a.clientY}}).css("display","none"),B.append(A)),f.startIndex=0,f.endIndex=0,H.on("scroll",function(){K?K=!1:y()&&f.$apply()}),c&&H.on(d,s),b.element(a).on("resize",t),f.$on("$destroy",function(){b.element(a).off("resize",t)}),f.$on("vsRepeatTrigger",q),f.$on("vsRepeatResize",function(){F=!0,r()});var Q,R,S;f.$watch(function(){"function"==typeof a.requestAnimationFrame?a.requestAnimationFrame(w):w()})}}}}}]),b.element(document.head).append([""].join(""))}(window,window.angular); \ No newline at end of file