diff --git a/demo/index.html b/demo/index.html
index 5b8e864..d8c8ab5 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -58,30 +58,21 @@
relative: { x: 15, y: 0 }
};
+ function resetScrollpoint(){
+ $scope.$broadcast('scrollpointShouldReset');
+ }
+
// watch toggle controls
- $scope.$watchGroup(['topSpacer', 'showAbsolute', 'shiftRelative', 'target.showAbsolute', 'target.showRelative'],
- function(){
- $scope.$broadcast('scrollpointShouldReset');
- });
+ $scope.$watchGroup(['topSpacer', 'showAbsolute', 'shiftRelative', 'target.showAbsolute', 'target.showRelative'], resetScrollpoint);
// watch co-ordinate collections
- $scope.$watchCollection('absolute', function(){
- $scope.$broadcast('scrollpointShouldReset');
- });
- $scope.$watchCollection('relative', function(){
- $scope.$broadcast('scrollpointShouldReset');
- });
- $scope.$watchCollection('target.absolute', function(){
- $scope.$broadcast('scrollpointShouldReset');
- });
- $scope.$watchCollection('target.relative', function(){
- $scope.$broadcast('scrollpointShouldReset');
- });
+ $scope.$watchCollection('absolute', resetScrollpoint);
+ $scope.$watchCollection('relative', resetScrollpoint);
+ $scope.$watchCollection('target.absolute', resetScrollpoint);
+ $scope.$watchCollection('target.relative', resetScrollpoint);
// initialize
- $timeout(function(){
- $scope.$broadcast('scrollpointShouldReset');
- }, 10);
+ $timeout( resetScrollpoint, 10 );
});
@@ -206,13 +197,15 @@
Scrollpoints
id="viewtrack-1"
-
- ui-scrollpoint="{{scrollpoint}}"
+
+ ui-scrollpoint
+ ui-scrollpoint-edge="{ top: '-25', bottom: '+25' }"
ui-scrollpoint-action="reportScroll"
-
+
ui-scrollpoint="{{scrollpoint}}"
+ ui-scrollpoint-edge="['top', 'bottom']"
ui-scrollpoint-class="my-scrollpoint"
@@ -221,6 +214,11 @@
Scrollpoints
ui-scrollpoint-class="ui-scrollpoint another-scrollpoint"
+
+ ui-scrollpoint
+ ui-scrollpoint-edge="{ top: '25%', bottom: '70%' }"
+
+
@@ -391,7 +389,6 @@
absolutely positioned parent
-
ui-scrollpoint
ui-scrollpoint-edge="bottom"
@@ -418,6 +415,28 @@
absolutely positioned parent
ui-scrollpoint-action="reportScroll"
+
+ ui-scrollpoint
+ ui-scrollpoint-edge="bottom"
+
+
+
+ ui-scrollpoint
+ ui-scrollpoint-edge="{ top: '-25', bottom: '+25' }"
+
+
+
+ ui-scrollpoint="{{scrollpoint}}"
+ ui-scrollpoint-edge="['bottom', 'top']"
+ ui-scrollpoint-class="my-scrollpoint"
+
+
+
+ ui-scrollpoint="{{scrollpoint}}"
+ ui-scrollpoint-edge="bottom"
+ ui-scrollpoint-class="ui-scrollpoint another-scrollpoint"
+
+
diff --git a/dist/scrollpoint.js b/dist/scrollpoint.js
index 84cf5c7..e01258b 100644
--- a/dist/scrollpoint.js
+++ b/dist/scrollpoint.js
@@ -1,7 +1,7 @@
/*!
* angular-ui-scrollpoint
* https://github.com/angular-ui/ui-scrollpoint
- * Version: 2.0.2 - 2016-01-03T02:19:46.904Z
+ * Version: 2.1.1 - 2016-02-22T01:35:08.609Z
* License: MIT
*/
@@ -32,33 +32,99 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
return {
require: ['uiScrollpoint', '^?uiScrollpointTarget'],
controller: function(){
+ var self = this;
this.$element = undefined;
this.$target = undefined;
this.hasTarget = false;
- this.edges = {top: true};
+ this.hit = undefined;
+ this.edges = { top: { top: true }}; // ui-scrollpoint on top edge of element with top edge of target
this.hitEdge = undefined;
- this.absolute = true;
- this.percent = false;
- this.shift = 0;
+ this.default_edge = {
+ absolute: false,
+ percent: false,
+ shift: 0
+ };
this.posCache = {};
+ this.ready = false;
this.enabled = true;
this.scrollpointClass = 'ui-scrollpoint';
this.actions = undefined;
+ function parseScrollpoint(scrollpoint){
+ var def = { shift: 0, absolute: false, percent: false };
+ if(scrollpoint && angular.isString(scrollpoint)) {
+ def.percent = (scrollpoint.charAt(scrollpoint.length-1) == '%');
+ if(def.percent) {
+ scrollpoint = scrollpoint.substr(0, scrollpoint.length-1);
+ }
+ if(scrollpoint.charAt(0) === '-') {
+ def.absolute = def.percent;
+ def.shift = -parseFloat(scrollpoint.substr(1));
+ }
+ else if(scrollpoint.charAt(0) === '+') {
+ def.absolute = def.percent;
+ def.shift = parseFloat(scrollpoint.substr(1));
+ }
+ else {
+ var parsed = parseFloat(scrollpoint);
+ if (!isNaN(parsed) && isFinite(parsed)) {
+ def.absolute = true;
+ def.shift = parsed;
+ }
+ }
+ }
+ else if(angular.isNumber(scrollpoint)){
+ return parseScrollpoint(scrollpoint.toString());
+ }
+ return def;
+ }
+
this.addEdge = function(view_edge, element_edge){
if(angular.isString(view_edge)){
if(angular.isUndefined(element_edge)){
element_edge = true;
}
if(view_edge == 'view'){
+ // view is a shorthand for matching top of element with bottom of view, and vice versa
this.addEdge('top', 'bottom');
this.addEdge('bottom', 'top');
}
else{
+ var edge, parsedEdge;
+ if(angular.isObject(element_edge)){
+ // the view_edge interacts with more than one element_edge
+ for(edge in element_edge){
+ // parse each element_edge definition (allows each element_edge to have its own scrollpoint with view_edge)
+ if(element_edge[edge] === true){
+ element_edge[edge] = true; // use the ui-scrollpoint default
+ }
+ else{
+ element_edge[edge] = parseScrollpoint(element_edge[edge]);
+ }
+ }
+ }
+ else if(element_edge == 'top' || element_edge == 'bottom'){
+ // simple top or bottom of element with 0 shift
+ edge = element_edge;
+ parsedEdge = parseScrollpoint();
+ element_edge = {};
+ element_edge[edge] = parsedEdge;
+ }
+ else if(element_edge === true){
+ element_edge = {};
+ element_edge[view_edge] = true; // use the ui-scrollpoint default
+ }
+ else{
+ // element_edge matches view_edge (ie. top of element interacts with top of view)
+ parsedEdge = parseScrollpoint(element_edge);
+ element_edge = {};
+ element_edge[view_edge] = parsedEdge;
+ }
+ // element_edge has been parsed
this.edges[view_edge] = element_edge;
}
}
@@ -76,33 +142,7 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
};
this.setScrollpoint = function(scrollpoint){
- if (!scrollpoint) {
- this.absolute = false;
- this.percent = false;
- this.shift = 0;
- } else if (typeof (scrollpoint) === 'string') {
- // charAt is generally faster than indexOf: http://jsperf.com/indexof-vs-charat
- this.percent = (scrollpoint.charAt(scrollpoint.length-1) == '%');
- if(this.percent){
- scrollpoint = scrollpoint.substr(0, scrollpoint.length-1);
- }
- if (scrollpoint.charAt(0) === '-') {
- this.absolute = this.percent;
- this.shift = -parseFloat(scrollpoint.substr(1));
- } else if (scrollpoint.charAt(0) === '+') {
- this.absolute = this.percent;
- this.shift = parseFloat(scrollpoint.substr(1));
- } else {
- var parsed = parseFloat(scrollpoint);
- if (!isNaN(parsed) && isFinite(parsed)) {
- this.absolute = true;
- this.shift = parsed;
- }
- }
- } else if (typeof (scrollpoint) === 'number') {
- this.setScrollpoint(scrollpoint.toString());
- return;
- }
+ this.default_edge = parseScrollpoint(scrollpoint);
};
this.setClass = function(_class){
@@ -121,7 +161,7 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
}
else if(angular.isArray(edges)){
this.edges = {};
- for(var i in edges){
+ for(var i=0; i < edges.length; i++){
this.addEdge(edges[i]);
}
}
@@ -133,7 +173,8 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
}
else{
// default
- this.edges = {top: true};
+ this.edges = {};
+ this.addEdge('top');
}
};
@@ -152,63 +193,117 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
}
};
- this.scrollEdgeHit = function(){
- var offset, hitEdge, flipOffset;
- for(var scroll_edge in this.edges){
- var scroll_top = (scroll_edge == 'top');
- var scroll_bottom = (scroll_edge == 'bottom');
-
- var elem_edge = this.edges[scroll_edge];
- var elem_top = (elem_edge == 'top');
- var elem_bottom = (elem_edge == 'bottom');
- if(elem_edge === true){
- if(scroll_top){ elem_top = true; }
- if(scroll_bottom){ elem_bottom = true; }
+ this.getEdge = function(scroll_edge, element_edge){
+ if(scroll_edge && element_edge){
+ if(this.edges[scroll_edge] && this.edges[scroll_edge][element_edge] && this.edges[scroll_edge][element_edge] !== true){
+ return this.edges[scroll_edge][element_edge];
+ }
+ }
+ else if(scroll_edge && !element_edge){
+ if(this.edges[scroll_edge]){
+ return this.edges[scroll_edge];
}
+ return;
+ }
+ return this.default_edge;
+ };
- var scrollOffset = this.getScrollOffset();
+ this.checkOffset = function(scroll_edge, elem_edge, edge){
+ var offset;
+ if(!edge){
+ edge = this.default_edge;
+ }
+
+ var scroll_bottom = (scroll_edge == 'bottom');
+ var elem_top = (elem_edge == 'top');
+ var elem_bottom = (elem_edge == 'bottom');
+
+ var scrollOffset = this.getScrollOffset();
+ if(scroll_bottom){
+ scrollOffset += this.getTargetHeight();
+ }
+
+ var checkOffset;
+ if(edge.absolute){
+ if(edge.percent){
+ checkOffset = edge.shift / 100.0 * this.getTargetScrollHeight();
+ }
+ else{
+ checkOffset = edge.shift;
+ }
if(scroll_bottom){
- scrollOffset += this.getTargetHeight();
+ checkOffset = this.getTargetContentHeight() - checkOffset;
+ if(this.hasTarget){
+ checkOffset += this.getTargetHeight();
+ }
}
+ }
+ else{
+ if(elem_top){
+ checkOffset = this.getElementTop();
+ }
+ else if(elem_bottom){
+ checkOffset = this.getElementBottom();
+ }
+ checkOffset += edge.shift;
+ }
- var checkOffset;
- if(this.absolute){
- if(this.percent){
- checkOffset = this.shift / 100.0 * this.getTargetScrollHeight();
- }
- else{
- checkOffset = this.shift;
- }
- if(scroll_bottom){
- checkOffset = this.getTargetContentHeight() - checkOffset;
- if(this.hasTarget){
- checkOffset += this.getTargetHeight();
+ offset = (scrollOffset - checkOffset);
+ if(scroll_bottom){
+ offset *= -1.0;
+ }
+ return offset;
+ };
+
+ this.scrollEdgeHit = function(){
+ var offset, edgeHit, absEdges, absEdgeHits;
+ var edge, scroll_edge, element_edge;
+ absEdges = 0;
+ absEdgeHits = {};
+ for(scroll_edge in this.edges){
+ for(element_edge in this.edges[scroll_edge]){
+ edge = this.getEdge(scroll_edge, element_edge);
+ var edge_offset = this.checkOffset(scroll_edge, element_edge, edge);
+
+ if(edge.absolute){
+ if(angular.isUndefined(absEdgeHits)){
+ absEdgeHits = {};
}
+ if(angular.isUndefined(absEdgeHits[scroll_edge])){
+ absEdgeHits[scroll_edge] = {};
+ }
+ absEdgeHits[scroll_edge][element_edge] = edge_offset;
+ absEdges++;
}
- }
- else{
- if(elem_top){
- checkOffset = this.getElementTop();
- }
- else if(elem_bottom){
- checkOffset = this.getElementBottom();
+ else if(angular.isUndefined(offset) || edge_offset > offset){
+ offset = edge_offset;
+ edgeHit = {scroll: scroll_edge, element: element_edge};
}
- checkOffset += this.shift;
}
-
- var edge_offset = (scrollOffset - checkOffset);
- if(scroll_bottom){
- edge_offset *= -1.0;
+ }
+ // special handling for absolute edges when no relative edges hit
+ if(absEdges && !edgeHit){
+ // in case there is more than one absolute edge, they all should pass to count a hit (allows for creating ranges where the scrollpoint is active)
+ var allPass = true;
+ offset = undefined;
+ for(scroll_edge in absEdgeHits){
+ for(element_edge in absEdgeHits[scroll_edge]){
+ if(absEdges > 1 && absEdgeHits[scroll_edge][element_edge] < 0){
+ allPass = false;
+ }
+ else if(angular.isUndefined(offset) || absEdgeHits[scroll_edge][element_edge] > offset){
+ offset = absEdgeHits[scroll_edge][element_edge];
+ edgeHit = {scroll: scroll_edge, element: element_edge};
+ }
+ }
}
-
- if(angular.isUndefined(offset) || edge_offset > offset){
- offset = edge_offset;
- hitEdge = scroll_edge;
- flipOffset = (scroll_bottom && this.absolute);
+ if(!allPass){
+ edgeHit = undefined;
+ offset = undefined;
}
}
- this.hitEdge = (offset >= 0) ? hitEdge : undefined;
- return offset*(flipOffset?-1.0:1.0);
+ this.hitEdge = ((offset >= 0) ? edgeHit : undefined);
+ return offset;
};
this.getScrollOffset = function(){
@@ -245,12 +340,66 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
this.cachePosition = function(){
this.posCache.top = this.getElementTop(true);
};
+
+ this.onScroll = function() {
+ if(!self.ready || !self.enabled){ return; }
+
+ var edgeHit = self.scrollEdgeHit();
+
+ // edgeHit >= 0 - scrollpoint is scrolled out of active view
+ // edgeHit < 0 - scrollpoint is in active view
+
+ // hit is toggled at the moment the scrollpoint is crossed
+
+ var fireActions = false;
+
+ if(edgeHit >= 0){
+ // SCROLLPOINT is OUT by edgeHit pixels
+ if(!self.hit){
+ // add the scrollpoint class
+ if(!self.$element.hasClass(self.scrollpointClass)){
+ self.$element.addClass(self.scrollpointClass);
+ }
+ fireActions = true;
+ self.hit = true;
+ }
+ }
+ else{
+ // SCROLLPOINT is IN by edgeHit pixels
+ if(self.hit || angular.isUndefined(self.hit)){
+ // remove the scrollpoint class
+ if(self.$element.hasClass(self.scrollpointClass)){
+ self.$element.removeClass(self.scrollpointClass);
+ }
+ fireActions = true;
+ self.hit = false;
+ }
+ self.cachePosition();
+ }
+
+ if(fireActions){
+ // fire the actions
+ if(self.actions){
+ for(var i=0; i < self.actions.length; i++){
+ self.actions[i](edgeHit, self.$element, (self.hitEdge ? self.hitEdge.scroll : undefined), (self.hitEdge ? self.hitEdge.element : undefined));
+ }
+ }
+ }
+ };
+
+ this.reset = function(){
+ $timeout(function(){
+ self.$element.removeClass(self.scrollpointClass);
+ self.hit = undefined;
+ self.hitEdge = undefined;
+ self.cachePosition();
+ self.onScroll();
+ });
+ };
},
link: function (scope, elm, attrs, Ctrl) {
var uiScrollpoint = Ctrl[0];
var uiScrollpointTarget = Ctrl[1];
- var ready = false;
- var hit = false;
var absoluteParent = false;
uiScrollpoint.setElement(elm);
@@ -259,14 +408,14 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
// base ui-scrollpoint (leave blank or set to: absolute, +, -, or %)
attrs.$observe('uiScrollpoint', function(scrollpoint){
uiScrollpoint.setScrollpoint(scrollpoint);
- onScroll();
+ uiScrollpoint.reset();
});
// ui-scrollpoint-enabled allows disabling the scrollpoint
attrs.$observe('uiScrollpointEnabled', function(scrollpointEnabled){
scrollpointEnabled = scope.$eval(scrollpointEnabled);
if(scrollpointEnabled != uiScrollpoint.enabled){
- reset();
+ uiScrollpoint.reset();
}
uiScrollpoint.enabled = scrollpointEnabled;
});
@@ -276,11 +425,11 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
scrollpointAbsolute = scope.$eval(scrollpointAbsolute);
if(scrollpointAbsolute != absoluteParent){
if(uiScrollpoint.$target){
- uiScrollpoint.$target.off('scroll', onScroll);
+ uiScrollpoint.$target.off('scroll', uiScrollpoint.onScroll);
}
uiScrollpoint.setTarget( (!scrollpointAbsolute && uiScrollpointTarget) ? uiScrollpointTarget.$element : null);
resetTarget();
- reset();
+ uiScrollpoint.reset();
}
absoluteParent = scrollpointAbsolute;
});
@@ -295,9 +444,9 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
// ui-scrollpoint-class class to add instead of ui-scrollpoint
attrs.$observe('uiScrollpointClass', function(scrollpointClass){
+ elm.removeClass(uiScrollpoint.scrollpointClass);
uiScrollpoint.setClass(scrollpointClass);
- hit = false;
- onScroll();
+ uiScrollpoint.reset();
});
// ui-scrollpoint-edge allows configuring which element and scroll edges match
@@ -312,74 +461,19 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
// assign it in controller
uiScrollpoint.setEdges(scrollpointEdge);
+ uiScrollpoint.reset();
}
});
- function onScroll() {
- if(!ready || !uiScrollpoint.enabled){ return; }
-
- var hitEdge = uiScrollpoint.hitEdge; // which edge did scrollpoint trigger at before
- var edgeHit = uiScrollpoint.scrollEdgeHit();
-
- // edgeHit >= 0 - scrollpoint is scrolled out of active view
- // edgeHit < 0 - scrollpoint is in active view
-
- // hit is toggled at the moment the scrollpoint is crossed
-
- var fireActions = false;
-
- if(edgeHit >= 0){
- // SCROLLPOINT is OUT by edgeHit pixels
- if(!hit){
- // add the scrollpoint class
- if(!elm.hasClass(uiScrollpoint.scrollpointClass)){
- elm.addClass(uiScrollpoint.scrollpointClass);
- }
- fireActions = true;
- hit = true;
- }
- }
- else{
- // SCROLLPOINT is IN by edgeHit pixels
- if(hit || angular.isUndefined(hit)){
- // remove the scrollpoint class
- if(elm.hasClass(uiScrollpoint.scrollpointClass)){
- elm.removeClass(uiScrollpoint.scrollpointClass);
- }
- fireActions = true;
- hit = false;
- }
- uiScrollpoint.cachePosition();
- }
-
- if(fireActions){
- // fire the actions
- if(uiScrollpoint.actions){
- for(var i in uiScrollpoint.actions){
- uiScrollpoint.actions[i](edgeHit, elm, uiScrollpoint.hitEdge || hitEdge);
- }
- }
- }
- }
-
- function reset() {
- $timeout(function(){
- elm.removeClass(uiScrollpoint.scrollpointClass);
- hit = undefined;
- uiScrollpoint.hitEdge = undefined;
- uiScrollpoint.cachePosition();
- onScroll();
- });
- }
function resetTarget() {
- uiScrollpoint.$target.on('scroll', onScroll);
+ uiScrollpoint.$target.on('scroll', uiScrollpoint.onScroll);
scope.$on('$destroy', function () {
- uiScrollpoint.$target.off('scroll', onScroll);
+ uiScrollpoint.$target.off('scroll', uiScrollpoint.onScroll);
});
}
resetTarget();
- elm.ready(function(){ ready=true; onScroll(); });
- scope.$on('scrollpointShouldReset', reset);
+ elm.ready(function(){ uiScrollpoint.ready=true; uiScrollpoint.onScroll(); });
+ scope.$on('scrollpointShouldReset', uiScrollpoint.reset);
}
};
}]).directive('uiScrollpointTarget', [function () {
diff --git a/dist/scrollpoint.min.js b/dist/scrollpoint.min.js
index 02650c7..7898bd8 100644
--- a/dist/scrollpoint.min.js
+++ b/dist/scrollpoint.min.js
@@ -1,7 +1,7 @@
/*!
* angular-ui-scrollpoint
* https://github.com/angular-ui/ui-scrollpoint
- * Version: 2.0.2 - 2016-01-03T02:19:46.904Z
+ * Version: 2.1.1 - 2016-02-22T01:35:08.609Z
* License: MIT
*/
-!function(){"use strict";angular.module("ui.scrollpoint",[]).directive("uiScrollpoint",["$window","$timeout",function(t,e){function i(){if(angular.isDefined(t.pageYOffset))return t.pageYOffset;var e=document.compatMode&&"BackCompat"!==document.compatMode?document.documentElement:document.body;return e.scrollTop}function s(){return t.document.body.scrollHeight-t.innerHeight}function n(e){return e?t.document.body.clientHeight:t.innerHeight}return{require:["uiScrollpoint","^?uiScrollpointTarget"],controller:function(){this.$element=void 0,this.$target=void 0,this.hasTarget=!1,this.edges={top:!0},this.hitEdge=void 0,this.absolute=!0,this.percent=!1,this.shift=0,this.posCache={},this.enabled=!0,this.scrollpointClass="ui-scrollpoint",this.actions=void 0,this.addEdge=function(t,e){angular.isString(t)&&(angular.isUndefined(e)&&(e=!0),"view"==t?(this.addEdge("top","bottom"),this.addEdge("bottom","top")):this.edges[t]=e)},this.addAction=function(t){t&&angular.isFunction(t)&&(angular.isUndefined(this.actions)?this.actions=[t]:-1==this.actions.indexOf(t)&&this.actions.push(t))},this.setScrollpoint=function(t){if(t){if("string"==typeof t)if(this.percent="%"==t.charAt(t.length-1),this.percent&&(t=t.substr(0,t.length-1)),"-"===t.charAt(0))this.absolute=this.percent,this.shift=-parseFloat(t.substr(1));else if("+"===t.charAt(0))this.absolute=this.percent,this.shift=parseFloat(t.substr(1));else{var e=parseFloat(t);!isNaN(e)&&isFinite(e)&&(this.absolute=!0,this.shift=e)}else if("number"==typeof t)return void this.setScrollpoint(t.toString())}else this.absolute=!1,this.percent=!1,this.shift=0},this.setClass=function(t){t||(t="ui-scrollpoint"),this.scrollpointClass=t},this.setEdges=function(t){if(angular.isString(t))this.edges={},this.addEdge(t);else if(angular.isArray(t)){this.edges={};for(var e in t)this.addEdge(t[e])}else if(angular.isObject(t)){this.edges={};for(var i in t)this.addEdge(i,t[i])}else this.edges={top:!0}},this.setElement=function(t){this.$element=t},this.setTarget=function(e){e?(this.$target=e,this.hasTarget=!0):(this.$target=angular.element(t),this.hasTarget=!1)},this.scrollEdgeHit=function(){var t,e,i;for(var s in this.edges){var n="top"==s,o="bottom"==s,r=this.edges[s],l="top"==r,a="bottom"==r;r===!0&&(n&&(l=!0),o&&(a=!0));var h=this.getScrollOffset();o&&(h+=this.getTargetHeight());var c;this.absolute?(c=this.percent?this.shift/100*this.getTargetScrollHeight():this.shift,o&&(c=this.getTargetContentHeight()-c,this.hasTarget&&(c+=this.getTargetHeight()))):(l?c=this.getElementTop():a&&(c=this.getElementBottom()),c+=this.shift);var g=h-c;o&&(g*=-1),(angular.isUndefined(t)||g>t)&&(t=g,e=s,i=o&&this.absolute)}return this.hitEdge=t>=0?e:void 0,t*(i?-1:1)},this.getScrollOffset=function(){return this.hasTarget?this.$target[0].scrollTop:i()},this.getTargetHeight=function(){return this.hasTarget?this.$target[0].offsetHeight:n()},this.getTargetContentHeight=function(){return this.hasTarget?this.$target[0].scrollHeight-this.$target[0].clientHeight:n(!0)},this.getTargetScrollHeight=function(){return this.hasTarget?this.$target[0].scrollHeight-this.$target[0].clientHeight:s()},this.getElementTop=function(t){if(!t&&angular.isDefined(this.posCache.top))return this.posCache.top;var e=this.$element[0].getBoundingClientRect(),i=e.top+this.getScrollOffset();if(this.hasTarget){var s=this.$target[0].getBoundingClientRect();i-=s.top}return i},this.getElementBottom=function(t){return this.getElementTop(t)+this.$element[0].offsetHeight},this.cachePosition=function(){this.posCache.top=this.getElementTop(!0)}},link:function(t,i,s,n){function o(){if(c&&a.enabled){var t=a.hitEdge,e=a.scrollEdgeHit(),s=!1;if(e>=0?g||(i.hasClass(a.scrollpointClass)||i.addClass(a.scrollpointClass),s=!0,g=!0):((g||angular.isUndefined(g))&&(i.hasClass(a.scrollpointClass)&&i.removeClass(a.scrollpointClass),s=!0,g=!1),a.cachePosition()),s&&a.actions)for(var n in a.actions)a.actions[n](e,i,a.hitEdge||t)}}function r(){e(function(){i.removeClass(a.scrollpointClass),g=void 0,a.hitEdge=void 0,a.cachePosition(),o()})}function l(){a.$target.on("scroll",o),t.$on("$destroy",function(){a.$target.off("scroll",o)})}var a=n[0],h=n[1],c=!1,g=!1,u=!1;a.setElement(i),a.setTarget(h?h.$element:null),s.$observe("uiScrollpoint",function(t){a.setScrollpoint(t),o()}),s.$observe("uiScrollpointEnabled",function(e){e=t.$eval(e),e!=a.enabled&&r(),a.enabled=e}),s.$observe("uiScrollpointAbsolute",function(e){e=t.$eval(e),e!=u&&(a.$target&&a.$target.off("scroll",o),a.setTarget(!e&&h?h.$element:null),l(),r()),u=e}),s.$observe("uiScrollpointAction",function(e){var i=t.$eval(e);i&&angular.isFunction(i)&&a.addAction(i)}),s.$observe("uiScrollpointClass",function(t){a.setClass(t),g=!1,o()}),s.$observe("uiScrollpointEdge",function(e){if(e){var i=["top","bottom","view"];-1==i.indexOf(e)&&(e=t.$eval(e)),a.setEdges(e)}}),l(),i.ready(function(){c=!0,o()}),t.$on("scrollpointShouldReset",r)}}}]).directive("uiScrollpointTarget",[function(){return{controller:["$element",function(t){this.$element=t}]}}])}();
\ No newline at end of file
+!function(){"use strict";angular.module("ui.scrollpoint",[]).directive("uiScrollpoint",["$window","$timeout",function(t,e){function i(){if(angular.isDefined(t.pageYOffset))return t.pageYOffset;var e=document.compatMode&&"BackCompat"!==document.compatMode?document.documentElement:document.body;return e.scrollTop}function s(){return t.document.body.scrollHeight-t.innerHeight}function n(e){return e?t.document.body.clientHeight:t.innerHeight}return{require:["uiScrollpoint","^?uiScrollpointTarget"],controller:function(){function o(t){var e={shift:0,absolute:!1,percent:!1};if(t&&angular.isString(t))if(e.percent="%"==t.charAt(t.length-1),e.percent&&(t=t.substr(0,t.length-1)),"-"===t.charAt(0))e.absolute=e.percent,e.shift=-parseFloat(t.substr(1));else if("+"===t.charAt(0))e.absolute=e.percent,e.shift=parseFloat(t.substr(1));else{var i=parseFloat(t);!isNaN(i)&&isFinite(i)&&(e.absolute=!0,e.shift=i)}else if(angular.isNumber(t))return o(t.toString());return e}var r=this;this.$element=void 0,this.$target=void 0,this.hasTarget=!1,this.hit=void 0,this.edges={top:{top:!0}},this.hitEdge=void 0,this.default_edge={absolute:!1,percent:!1,shift:0},this.posCache={},this.ready=!1,this.enabled=!0,this.scrollpointClass="ui-scrollpoint",this.actions=void 0,this.addEdge=function(t,e){if(angular.isString(t))if(angular.isUndefined(e)&&(e=!0),"view"==t)this.addEdge("top","bottom"),this.addEdge("bottom","top");else{var i,s;if(angular.isObject(e))for(i in e)e[i]=e[i]===!0?!0:o(e[i]);else"top"==e||"bottom"==e?(i=e,s=o(),e={},e[i]=s):e===!0?(e={},e[t]=!0):(s=o(e),e={},e[t]=s);this.edges[t]=e}},this.addAction=function(t){t&&angular.isFunction(t)&&(angular.isUndefined(this.actions)?this.actions=[t]:-1==this.actions.indexOf(t)&&this.actions.push(t))},this.setScrollpoint=function(t){this.default_edge=o(t)},this.setClass=function(t){t||(t="ui-scrollpoint"),this.scrollpointClass=t},this.setEdges=function(t){if(angular.isString(t))this.edges={},this.addEdge(t);else if(angular.isArray(t)){this.edges={};for(var e=0;et)&&(t=l,e={scroll:o,element:r})}if(i&&!e){var a=!0;t=void 0;for(o in s)for(r in s[o])i>1&&s[o][r]<0?a=!1:(angular.isUndefined(t)||s[o][r]>t)&&(t=s[o][r],e={scroll:o,element:r});a||(e=void 0,t=void 0)}return this.hitEdge=t>=0?e:void 0,t},this.getScrollOffset=function(){return this.hasTarget?this.$target[0].scrollTop:i()},this.getTargetHeight=function(){return this.hasTarget?this.$target[0].offsetHeight:n()},this.getTargetContentHeight=function(){return this.hasTarget?this.$target[0].scrollHeight-this.$target[0].clientHeight:n(!0)},this.getTargetScrollHeight=function(){return this.hasTarget?this.$target[0].scrollHeight-this.$target[0].clientHeight:s()},this.getElementTop=function(t){if(!t&&angular.isDefined(this.posCache.top))return this.posCache.top;var e=this.$element[0].getBoundingClientRect(),i=e.top+this.getScrollOffset();if(this.hasTarget){var s=this.$target[0].getBoundingClientRect();i-=s.top}return i},this.getElementBottom=function(t){return this.getElementTop(t)+this.$element[0].offsetHeight},this.cachePosition=function(){this.posCache.top=this.getElementTop(!0)},this.onScroll=function(){if(r.ready&&r.enabled){var t=r.scrollEdgeHit(),e=!1;if(t>=0?r.hit||(r.$element.hasClass(r.scrollpointClass)||r.$element.addClass(r.scrollpointClass),e=!0,r.hit=!0):((r.hit||angular.isUndefined(r.hit))&&(r.$element.hasClass(r.scrollpointClass)&&r.$element.removeClass(r.scrollpointClass),e=!0,r.hit=!1),r.cachePosition()),e&&r.actions)for(var i=0;i offset){
+ offset = edge_offset;
+ edgeHit = {scroll: scroll_edge, element: element_edge};
}
- checkOffset += this.shift;
}
-
- var edge_offset = (scrollOffset - checkOffset);
- if(scroll_bottom){
- edge_offset *= -1.0;
+ }
+ // special handling for absolute edges when no relative edges hit
+ if(absEdges && !edgeHit){
+ // in case there is more than one absolute edge, they all should pass to count a hit (allows for creating ranges where the scrollpoint is active)
+ var allPass = true;
+ offset = undefined;
+ for(scroll_edge in absEdgeHits){
+ for(element_edge in absEdgeHits[scroll_edge]){
+ if(absEdges > 1 && absEdgeHits[scroll_edge][element_edge] < 0){
+ allPass = false;
+ }
+ else if(angular.isUndefined(offset) || absEdgeHits[scroll_edge][element_edge] > offset){
+ offset = absEdgeHits[scroll_edge][element_edge];
+ edgeHit = {scroll: scroll_edge, element: element_edge};
+ }
+ }
}
-
- if(angular.isUndefined(offset) || edge_offset > offset){
- offset = edge_offset;
- hitEdge = scroll_edge;
- flipOffset = (scroll_bottom && this.absolute);
+ if(!allPass){
+ edgeHit = undefined;
+ offset = undefined;
}
}
- this.hitEdge = (offset >= 0) ? hitEdge : undefined;
- return offset*(flipOffset?-1.0:1.0);
+ this.hitEdge = ((offset >= 0) ? edgeHit : undefined);
+ return offset;
};
this.getScrollOffset = function(){
@@ -235,12 +330,66 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
this.cachePosition = function(){
this.posCache.top = this.getElementTop(true);
};
+
+ this.onScroll = function() {
+ if(!self.ready || !self.enabled){ return; }
+
+ var edgeHit = self.scrollEdgeHit();
+
+ // edgeHit >= 0 - scrollpoint is scrolled out of active view
+ // edgeHit < 0 - scrollpoint is in active view
+
+ // hit is toggled at the moment the scrollpoint is crossed
+
+ var fireActions = false;
+
+ if(edgeHit >= 0){
+ // SCROLLPOINT is OUT by edgeHit pixels
+ if(!self.hit){
+ // add the scrollpoint class
+ if(!self.$element.hasClass(self.scrollpointClass)){
+ self.$element.addClass(self.scrollpointClass);
+ }
+ fireActions = true;
+ self.hit = true;
+ }
+ }
+ else{
+ // SCROLLPOINT is IN by edgeHit pixels
+ if(self.hit || angular.isUndefined(self.hit)){
+ // remove the scrollpoint class
+ if(self.$element.hasClass(self.scrollpointClass)){
+ self.$element.removeClass(self.scrollpointClass);
+ }
+ fireActions = true;
+ self.hit = false;
+ }
+ self.cachePosition();
+ }
+
+ if(fireActions){
+ // fire the actions
+ if(self.actions){
+ for(var i=0; i < self.actions.length; i++){
+ self.actions[i](edgeHit, self.$element, (self.hitEdge ? self.hitEdge.scroll : undefined), (self.hitEdge ? self.hitEdge.element : undefined));
+ }
+ }
+ }
+ };
+
+ this.reset = function(){
+ $timeout(function(){
+ self.$element.removeClass(self.scrollpointClass);
+ self.hit = undefined;
+ self.hitEdge = undefined;
+ self.cachePosition();
+ self.onScroll();
+ });
+ };
},
link: function (scope, elm, attrs, Ctrl) {
var uiScrollpoint = Ctrl[0];
var uiScrollpointTarget = Ctrl[1];
- var ready = false;
- var hit = false;
var absoluteParent = false;
uiScrollpoint.setElement(elm);
@@ -249,14 +398,14 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
// base ui-scrollpoint (leave blank or set to: absolute, +, -, or %)
attrs.$observe('uiScrollpoint', function(scrollpoint){
uiScrollpoint.setScrollpoint(scrollpoint);
- onScroll();
+ uiScrollpoint.reset();
});
// ui-scrollpoint-enabled allows disabling the scrollpoint
attrs.$observe('uiScrollpointEnabled', function(scrollpointEnabled){
scrollpointEnabled = scope.$eval(scrollpointEnabled);
if(scrollpointEnabled != uiScrollpoint.enabled){
- reset();
+ uiScrollpoint.reset();
}
uiScrollpoint.enabled = scrollpointEnabled;
});
@@ -266,11 +415,11 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
scrollpointAbsolute = scope.$eval(scrollpointAbsolute);
if(scrollpointAbsolute != absoluteParent){
if(uiScrollpoint.$target){
- uiScrollpoint.$target.off('scroll', onScroll);
+ uiScrollpoint.$target.off('scroll', uiScrollpoint.onScroll);
}
uiScrollpoint.setTarget( (!scrollpointAbsolute && uiScrollpointTarget) ? uiScrollpointTarget.$element : null);
resetTarget();
- reset();
+ uiScrollpoint.reset();
}
absoluteParent = scrollpointAbsolute;
});
@@ -285,9 +434,9 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
// ui-scrollpoint-class class to add instead of ui-scrollpoint
attrs.$observe('uiScrollpointClass', function(scrollpointClass){
+ elm.removeClass(uiScrollpoint.scrollpointClass);
uiScrollpoint.setClass(scrollpointClass);
- hit = false;
- onScroll();
+ uiScrollpoint.reset();
});
// ui-scrollpoint-edge allows configuring which element and scroll edges match
@@ -302,74 +451,19 @@ angular.module('ui.scrollpoint', []).directive('uiScrollpoint', ['$window', '$ti
// assign it in controller
uiScrollpoint.setEdges(scrollpointEdge);
+ uiScrollpoint.reset();
}
});
- function onScroll() {
- if(!ready || !uiScrollpoint.enabled){ return; }
-
- var hitEdge = uiScrollpoint.hitEdge; // which edge did scrollpoint trigger at before
- var edgeHit = uiScrollpoint.scrollEdgeHit();
-
- // edgeHit >= 0 - scrollpoint is scrolled out of active view
- // edgeHit < 0 - scrollpoint is in active view
-
- // hit is toggled at the moment the scrollpoint is crossed
-
- var fireActions = false;
-
- if(edgeHit >= 0){
- // SCROLLPOINT is OUT by edgeHit pixels
- if(!hit){
- // add the scrollpoint class
- if(!elm.hasClass(uiScrollpoint.scrollpointClass)){
- elm.addClass(uiScrollpoint.scrollpointClass);
- }
- fireActions = true;
- hit = true;
- }
- }
- else{
- // SCROLLPOINT is IN by edgeHit pixels
- if(hit || angular.isUndefined(hit)){
- // remove the scrollpoint class
- if(elm.hasClass(uiScrollpoint.scrollpointClass)){
- elm.removeClass(uiScrollpoint.scrollpointClass);
- }
- fireActions = true;
- hit = false;
- }
- uiScrollpoint.cachePosition();
- }
-
- if(fireActions){
- // fire the actions
- if(uiScrollpoint.actions){
- for(var i in uiScrollpoint.actions){
- uiScrollpoint.actions[i](edgeHit, elm, uiScrollpoint.hitEdge || hitEdge);
- }
- }
- }
- }
-
- function reset() {
- $timeout(function(){
- elm.removeClass(uiScrollpoint.scrollpointClass);
- hit = undefined;
- uiScrollpoint.hitEdge = undefined;
- uiScrollpoint.cachePosition();
- onScroll();
- });
- }
function resetTarget() {
- uiScrollpoint.$target.on('scroll', onScroll);
+ uiScrollpoint.$target.on('scroll', uiScrollpoint.onScroll);
scope.$on('$destroy', function () {
- uiScrollpoint.$target.off('scroll', onScroll);
+ uiScrollpoint.$target.off('scroll', uiScrollpoint.onScroll);
});
}
resetTarget();
- elm.ready(function(){ ready=true; onScroll(); });
- scope.$on('scrollpointShouldReset', reset);
+ elm.ready(function(){ uiScrollpoint.ready=true; uiScrollpoint.onScroll(); });
+ scope.$on('scrollpointShouldReset', uiScrollpoint.reset);
}
};
}]).directive('uiScrollpointTarget', [function () {