2016-05-07 10:54:44 +03:00
|
|
|
'use strict';
|
2016-05-25 18:34:31 +03:00
|
|
|
import { Injectable, EventEmitter, Output } from '@angular/core';
|
2016-08-28 21:46:10 +03:00
|
|
|
import { BrowserDomAdapter as DOM } from '../utils/browser-adapter';
|
2016-05-25 18:34:31 +03:00
|
|
|
import { OptionsService } from './options.service';
|
2016-08-22 12:18:56 +03:00
|
|
|
import { throttle } from '../utils/helpers';
|
2016-05-07 10:54:44 +03:00
|
|
|
|
|
|
|
export const INVIEW_POSITION = {
|
|
|
|
ABOVE : 1,
|
|
|
|
BELLOW: -1,
|
|
|
|
INVIEW: 0
|
|
|
|
};
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
export class ScrollService {
|
2016-05-25 18:34:31 +03:00
|
|
|
scrollYOffset: any;
|
|
|
|
$scrollParent: any;
|
|
|
|
@Output() scroll = new EventEmitter();
|
|
|
|
private prevOffsetY: number;
|
|
|
|
private _cancel:any;
|
2016-08-28 21:46:10 +03:00
|
|
|
constructor(optionsService:OptionsService) {
|
2016-05-07 10:54:44 +03:00
|
|
|
this.scrollYOffset = () => optionsService.options.scrollYOffset();
|
|
|
|
this.$scrollParent = optionsService.options.$scrollParent;
|
|
|
|
this.scroll = new EventEmitter();
|
|
|
|
this.bind();
|
|
|
|
}
|
|
|
|
|
|
|
|
scrollY() {
|
2016-06-13 20:54:24 +03:00
|
|
|
return (this.$scrollParent.pageYOffset != undefined) ? this.$scrollParent.pageYOffset : this.$scrollParent.scrollTop;
|
2016-05-07 10:54:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* returns 1 if element if above the view, 0 if in view and -1 below the view */
|
2016-10-31 14:34:42 +03:00
|
|
|
getElementPos($el, inverted=false) {
|
2016-10-23 20:18:42 +03:00
|
|
|
let scrollYOffset = this.scrollYOffset();
|
2016-10-31 14:34:42 +03:00
|
|
|
let mul = inverted ? -1 : 1;
|
|
|
|
if (mul*Math.floor($el.getBoundingClientRect().top) > mul*scrollYOffset) {
|
2016-05-07 10:54:44 +03:00
|
|
|
return INVIEW_POSITION.ABOVE;
|
|
|
|
}
|
|
|
|
|
2016-10-31 14:34:42 +03:00
|
|
|
if (mul*$el.getBoundingClientRect().bottom <= mul*scrollYOffset) {
|
2016-05-07 10:54:44 +03:00
|
|
|
return INVIEW_POSITION.BELLOW;
|
|
|
|
}
|
|
|
|
return INVIEW_POSITION.INVIEW;
|
|
|
|
}
|
|
|
|
|
|
|
|
scrollTo($el) {
|
|
|
|
// TODO: rewrite this to use offsetTop as more reliable solution
|
|
|
|
let subjRect = $el.getBoundingClientRect();
|
|
|
|
let offset = this.scrollY() + subjRect.top - this.scrollYOffset() + 1;
|
|
|
|
if (this.$scrollParent.scrollTo) {
|
|
|
|
this.$scrollParent.scrollTo(0, offset);
|
|
|
|
} else {
|
|
|
|
this.$scrollParent.scrollTop = offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scrollHandler(evt) {
|
|
|
|
let isScrolledDown = (this.scrollY() - this.prevOffsetY > 0);
|
|
|
|
this.prevOffsetY = this.scrollY();
|
|
|
|
this.scroll.next({isScrolledDown, evt});
|
|
|
|
}
|
|
|
|
|
|
|
|
bind() {
|
|
|
|
this.prevOffsetY = this.scrollY();
|
2016-08-28 21:46:10 +03:00
|
|
|
this._cancel = DOM.onAndCancel(this.$scrollParent, 'scroll',
|
2016-08-22 12:18:56 +03:00
|
|
|
throttle((evt) => { this.scrollHandler(evt); }, 100, this));
|
2016-05-07 10:54:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
unbind() {
|
|
|
|
this._cancel();
|
|
|
|
}
|
|
|
|
}
|