diff --git a/README.md b/README.md index ced45b0..57c4c04 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ example: - the vsRepeat directive must be applied to a direct parent of an element with `ngRepeat` - the value of vsRepeat attribute is the single element's height/width measured in pixels. If none provided, the directive will compute it automatically - + ###OPTIONAL PARAMETERS (attributes): - `vs-scroll-parent="selector"` - selector to the scrollable container. The directive will look for a closest parent matching the given selector (defaults to the current element) @@ -57,7 +57,8 @@ example: - `vs-excess="value"` - an integer number representing the number of elements to be rendered outside of the current container's viewport (defaults to 2) - `vs-size-property="propertyName"` - a property name of the items in collection that is a number denoting the element size (in pixels) - `vs-autoresize` - use this attribute without `vs-size-property` and without specifying element's size. The automatically computed element style will readjust upon window resize if the size is dependable on the viewport size +- `vs-scroll-settings` - an object with 2 possible properties: `scrollIndex: "value"` - index of the item that should be scrolled to; the exact position of this item in the viewport may be further defined by `scrollIndexPosition: "value"` - a position where the element at `scrollIndex` index will be scrolled to; either a number of pixels or one of the following strings: 'top', 'middle', 'bottom', 'inview' is the same as 'inview#top', 'inview#middle', 'inview#bottom', 'inview#auto'; the 'inview#\' settings means that if the item is already in the view, nothing is scrolled, but if it is not, then the item will be scrolled accordingly (to be in the \); position 'auto' means that it will be either 'top' or 'bottom' depending on what is closer to the current item position ###EVENTS: -- `vsRepeatTrigger` - an event the directive listens for to manually trigger reinitialization -- `vsRepeatReinitialized` - an event the directive emits upon reinitialization done +- `vsRepeatTrigger` - an event the directive listens for to manually trigger reinitialization; it may receive additional argument - an object with two properties: `scrollIndex` and `scrollIndexPosition` - their meaning is the same as in the optional attribute `vs-scroll-settings` +- `vsRepeatReinitialized` - an event the directive emits upon reinitialization done; the listener may accepts three arguments: `event`, `startIndex` and `endIndex` diff --git a/src/angular-vs-repeat.js b/src/angular-vs-repeat.js index 11e34d7..1e9ff30 100644 --- a/src/angular-vs-repeat.js +++ b/src/angular-vs-repeat.js @@ -124,6 +124,8 @@ positioningPropertyTransform = $$horizontal ? 'translateX' : 'translateY', positioningProperty = $$horizontal ? 'left' : 'top', + localScrollTrigger = false, + clientSize = $$horizontal ? 'clientWidth' : 'clientHeight', offsetSize = $$horizontal ? 'offsetWidth' : 'offsetHeight', scrollPos = $$horizontal ? 'scrollLeft' : 'scrollTop'; @@ -138,10 +140,23 @@ $scope.offsetBefore = 0; $scope.offsetAfter = 0; $scope.excess = 2; + $scope.scrollSettings = { + scrollIndex: 0, + scrollIndexPosition: 'top', + }; + + $scope.$watch($attrs.vsScrollSettings, function(newValue, oldValue) { + if (typeof newValue === 'undefined') { + return; + } + $scope.scrollSettings = newValue; + reinitialize($scope.scrollSettings); + }, true); Object.keys(attributesDictionary).forEach(function(key){ if($attrs[key]){ $attrs.$observe(key, function(value){ + // '+' serves for getting a number from the string as the attributes are always strings $scope[attributesDictionary[key]] = +value; reinitialize(); }); @@ -154,7 +169,7 @@ refresh(); }); - function refresh(){ + function refresh(event, data){ if(!originalCollection || originalCollection.length < 1){ $scope[collectionName] = []; originalLength = 0; @@ -179,7 +194,7 @@ setAutoSize(); } - reinitialize(); + reinitialize(data); } function setAutoSize(){ @@ -268,8 +283,16 @@ $scope.endIndex = 0; $scrollParent.on('scroll', function scrollHandler(e){ - if(updateInnerCollection()) - $scope.$apply(); + // Check if the scrolling was triggerred by a local action to avoid + // unnecessary inner collection updating + if (localScrollTrigger) { + localScrollTrigger = false; + } + else { + if(updateInnerCollection()) { + $scope.$apply(); + } + } }); if(isMacOS){ @@ -305,15 +328,15 @@ var _prevStartIndex, _prevEndIndex; - function reinitialize(){ + function reinitialize(data){ _prevStartIndex = void 0; _prevEndIndex = void 0; - updateInnerCollection(); + updateInnerCollection(data); resizeFillElement(sizesPropertyExists ? $scope.sizesCumulative[originalLength] : $scope.elementSize*originalLength ); - $scope.$emit('vsRepeatReinitialized'); + $scope.$emit('vsRepeatReinitialized', $scope.startIndex, $scope.endIndex); } function resizeFillElement(size){ @@ -363,39 +386,220 @@ reinitOnClientHeightChange(); }); - function updateInnerCollection(){ - if(sizesPropertyExists){ - $scope.startIndex = 0; - while($scope.sizesCumulative[$scope.startIndex] < $scrollParent[0][scrollPos] - $scope.offsetBefore) - $scope.startIndex++; - if($scope.startIndex > 0) $scope.startIndex--; + // Scroll to required position + // scrollTo - number of pixels to be scrolled to + function scrollToPosition(scrollTo) { + var scrolled = false; + if (scrollTo !== undefined && (typeof scrollTo) === 'number') { + // Set the position to be scrolled to + scrolled = Math.max(scrollTo, 0); + + // Is there a scroll change? + if ($scrollParent[0][scrollPos] !== scrolled) { + $scrollParent[0][scrollPos] = scrolled; + localScrollTrigger = true; + } + else { + scrolled = false; + } - $scope.endIndex = $scope.startIndex; - while($scope.sizesCumulative[$scope.endIndex] < $scrollParent[0][scrollPos] - $scope.offsetBefore + $scrollParent[0][clientSize]) - $scope.endIndex++; + // Emit the event + $scope.$emit('vsRepeatScrolled', scrolled); } - else{ - $scope.startIndex = Math.max( - Math.floor( - ($scrollParent[0][scrollPos] - $scope.offsetBefore) / $scope.elementSize + $scope.excess/2 - ) - $scope.excess, - 0 - ); - - $scope.endIndex = Math.min( - $scope.startIndex + Math.ceil( - $scrollParent[0][clientSize] / $scope.elementSize - ) + $scope.excess, - originalLength - ); + return scrolled; + } + + function updateInnerCollection(data){ + + var scrollChange = true, + position, + visibleStartIndex; + + if (data && data.scrollIndex !== undefined) { + if (typeof $scope.scrollSettings !== 'undefined') { + $scope.scrollSettings.scrollIndex = data.scrollIndex; + } + + // 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) { + if (typeof $scope.scrollSettings !== 'undefined') { + $scope.scrollSettings.scrollIndexPosition = data.scrollIndexPosition; + } + position = 0; + switch (typeof data.scrollIndexPosition) { + case 'number': + position = data.scrollIndexPosition + $scope.offsetBefore; + break; + case 'string': + switch (data.scrollIndexPosition) { + case 'top': + position = $scope.offsetBefore; + break; + case 'middle': + position = ($scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex]) / 2; + break; + case 'bottom': + position = $scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex] - $scope.offsetAfter; + break; + case 'inview': + case 'inview#top': + case 'inview#middle': + case 'inview#bottom': + 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])) { + scrollChange = false; + // The current item scroll position + position = $scope.sizesCumulative[data.scrollIndex] - $scrollParent[0][scrollPos]; + } + // The item is out of the viewport + else { + if (data.scrollIndexPosition === 'inview#top' || data.scrollIndexPosition === 'inview') { + // Get it at the top + position = $scope.offsetBefore; + } + if (data.scrollIndexPosition === 'inview#bottom') { + // Get it at the bottom + position = $scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex] + $scope.offsetAfter; + } + if (data.scrollIndexPosition === 'inview#middle') { + // Get it at the middle + position = ($scrollParent[0][clientSize] - $scope.sizes[data.scrollIndex]) / 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; + } + else { + position = $scope.offsetBefore; + } + } + } + break; + default: + console.warn('Incorrect scrollIndexPosition string value'); + break; + } + break; + default: + console.warn('Incorrect scrollIndexPosition type'); + break; + } + } + else { + // 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]; + } + + $scope.startIndex = data.scrollIndex; + + if(sizesPropertyExists){ + + while($scope.sizesCumulative[$scope.startIndex] > $scope.sizesCumulative[data.scrollIndex] - position) + { + $scope.startIndex--; + } + // The real first item in the view + visibleStartIndex = $scope.startIndex; + // Adjust the start index according to the excess + $scope.startIndex = Math.max( + Math.floor($scope.startIndex - ($scope.excess / 2)), + 0 + ); + + $scope.endIndex = $scope.startIndex; + while($scope.sizesCumulative[$scope.endIndex] < $scope.sizesCumulative[visibleStartIndex] - $scope.offsetBefore + $scrollParent[0][clientSize]) { + $scope.endIndex++; + } + // Adjust the end index according to the excess + $scope.endIndex = Math.min( + Math.ceil($scope.endIndex + ($scope.excess / 2)), + originalLength + ); + + } + else { + + while(($scope.startIndex * $scope.elementSize) > (data.scrollIndex * $scope.elementSize) - position) + { + $scope.startIndex--; + } + // The real first item in the view + visibleStartIndex = $scope.startIndex; + $scope.startIndex = Math.max( + Math.floor($scope.startIndex - ($scope.excess / 2)), + 0 + ); + + $scope.endIndex = Math.min( + $scope.startIndex + Math.ceil($scrollParent[0][clientSize] / $scope.elementSize) + $scope.excess / 2, + originalLength + ); + + } } + else { + if(sizesPropertyExists){ + $scope.startIndex = 0; + while($scope.sizesCumulative[$scope.startIndex] < $scrollParent[0][scrollPos] - $scope.offsetBefore) { + $scope.startIndex++; + } + if($scope.startIndex > 0) { $scope.startIndex--; } + // Adjust the start index according to the excess + $scope.startIndex = Math.max( + Math.floor($scope.startIndex - $scope.excess / 2), + 0 + ); + + $scope.endIndex = $scope.startIndex; + while($scope.sizesCumulative[$scope.endIndex] < $scrollParent[0][scrollPos] - $scope.offsetBefore + $scrollParent[0][clientSize]) { + $scope.endIndex++; + } + // Adjust the end index according to the excess + $scope.endIndex = Math.min( + Math.ceil($scope.endIndex + $scope.excess / 2), + originalLength + ); + } + else{ + $scope.startIndex = Math.max( + Math.floor( + ($scrollParent[0][scrollPos] - $scope.offsetBefore) / $scope.elementSize + $scope.excess / 2 + ) - $scope.excess, + 0 + ); + + $scope.endIndex = Math.min( + $scope.startIndex + Math.ceil( + $scrollParent[0][clientSize] / $scope.elementSize + ) + $scope.excess, + originalLength + ); + } + } + + var scrolled = false; + if (data !== undefined && data.scrollIndex !== undefined && position !== undefined && scrollChange) { + // Scroll to the requested position + scrolled = scrollToPosition($scope.sizesCumulative[data.scrollIndex] - position); + } var digestRequired = $scope.startIndex !== _prevStartIndex || $scope.endIndex !== _prevEndIndex; - if(digestRequired) + if(digestRequired) { $scope[collectionName] = originalCollection.slice($scope.startIndex, $scope.endIndex); + // Emit the event + $scope.$emit('vsRepeatInnerCollectionUpdated', $scope.startIndex, $scope.endIndex, _prevStartIndex, _prevEndIndex); + } + _prevStartIndex = $scope.startIndex; _prevEndIndex = $scope.endIndex; diff --git a/src/angular-vs-repeat.min.js b/src/angular-vs-repeat.min.js index b83fbca..57f7b95 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(){if(!C||C.length<1)return f[o]=[],y=0,v(0),void(f.sizesCumulative=[0]);if(y=C.length,F){f.sizes=C.map(function(a){return a[i.vsSizeProperty]});var a=0;f.sizesCumulative=f.sizes.map(function(b){var c=a;return a+=b,c}),f.sizesCumulative.push(a)}r(),u()}function r(){E&&f.$$postDigest(function(){if(h[0].offsetHeight||h[0].offsetWidth)for(var a=h.children(),b=0;bb.clientWidth||b.scrollHeight>b.clientHeight)&&z.css("display","block")}function t(){"undefined"!=typeof i.vsAutoresize&&(E=!0,r(),f.$root&&!f.$root.$$phase&&f.$apply()),x()&&f.$apply()}function u(){O=void 0,P=void 0,x(),v(F?f.sizesCumulative[y]:f.elementSize*y),f.$emit("vsRepeatReinitialized")}function v(a){if(D){if(A.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 A.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=G[0][J];a!==Q&&(u(),f.$root&&!f.$root.$$phase&&f.$apply()),Q=a}function x(){if(F){for(f.startIndex=0;f.sizesCumulative[f.startIndex]0&&f.startIndex--,f.endIndex=f.startIndex;f.sizesCumulative[f.endIndex]').css({position:"relative","min-height":"100%","min-width":"100%"}),h.append(A),e(A)(f),f.$fillElement=A;var N={};c&&(z=b.element('
').on(d,function(a){a.preventDefault(),a.stopPropagation(),a.originalEvent&&(a=a.originalEvent),G[0].scrollLeft+=a.deltaX||-a.wheelDeltaX,G[0].scrollTop+=a.deltaY||-a.wheelDeltaY}).on("mousemove",function(a){(N.x!==a.clientX||N.y!==a.clientY)&&b.element(this).css("display","none"),N={x:a.clientX,y:a.clientY}}).css("display","none"),A.append(z)),f.startIndex=0,f.endIndex=0,G.on("scroll",function(){x()&&f.$apply()}),c&&G.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(){E=!0,r()});var O,P,Q;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=!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