2015-12-26 20:44:39 +03:00
|
|
|
'use strict';
|
|
|
|
|
2016-06-15 21:48:04 +03:00
|
|
|
import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core';
|
2016-08-28 21:46:10 +03:00
|
|
|
import { BrowserDomAdapter as DOM } from '../../../utils/browser-adapter';
|
2015-12-26 20:44:39 +03:00
|
|
|
|
2016-01-21 01:09:42 +03:00
|
|
|
@Directive({
|
2016-06-15 21:48:04 +03:00
|
|
|
selector: '[sticky-sidebar]'
|
2015-12-26 20:44:39 +03:00
|
|
|
})
|
2016-06-15 21:48:04 +03:00
|
|
|
export class StickySidebar implements OnInit, OnDestroy {
|
2016-05-25 18:34:31 +03:00
|
|
|
$element: any;
|
|
|
|
cancelScrollBinding: any;
|
|
|
|
$redocEl: any;
|
|
|
|
@Input() scrollParent:any;
|
|
|
|
@Input() scrollYOffset:any;
|
2016-06-13 20:54:24 +03:00
|
|
|
|
2016-08-28 21:46:10 +03:00
|
|
|
constructor(elementRef:ElementRef) {
|
2016-02-10 16:48:07 +03:00
|
|
|
this.$element = elementRef.nativeElement;
|
2015-12-26 20:44:39 +03:00
|
|
|
|
|
|
|
// initial styling
|
2016-08-28 21:46:10 +03:00
|
|
|
DOM.setStyle(this.$element, 'position', 'absolute');
|
|
|
|
DOM.setStyle(this.$element, 'top', '0');
|
|
|
|
DOM.setStyle(this.$element, 'bottom', '0');
|
|
|
|
DOM.setStyle(this.$element, 'max-height', '100%');
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bind() {
|
2016-08-28 21:46:10 +03:00
|
|
|
this.cancelScrollBinding = DOM.onAndCancel(this.scrollParent, 'scroll', () => { this.updatePosition(); });
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
unbind() {
|
2016-06-13 20:54:24 +03:00
|
|
|
if (this.cancelScrollBinding) this.cancelScrollBinding();
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
updatePosition() {
|
2016-08-31 23:34:14 +03:00
|
|
|
var stuck = false;
|
2016-02-10 16:48:07 +03:00
|
|
|
if ( this.scrollY + this.scrollYOffset() >= this.$redocEl.offsetTop) {
|
2015-12-26 20:44:39 +03:00
|
|
|
this.stick();
|
2016-08-31 23:34:14 +03:00
|
|
|
stuck = true;
|
2015-12-26 20:44:39 +03:00
|
|
|
} else {
|
|
|
|
this.unstick();
|
|
|
|
}
|
2016-08-31 23:34:14 +03:00
|
|
|
|
|
|
|
if ( this.scrollY + window.innerHeight - this.scrollYOffset() >= this.$redocEl.scrollHeight) {
|
|
|
|
this.stickBottom();
|
|
|
|
stuck = true;
|
|
|
|
} else {
|
|
|
|
this.unstickBottom();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!stuck) {
|
|
|
|
DOM.setStyle(this.$element, 'position', 'absolute');
|
|
|
|
}
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
stick() {
|
2016-08-28 21:46:10 +03:00
|
|
|
DOM.setStyle(this.$element, 'position', 'fixed');
|
|
|
|
DOM.setStyle(this.$element, 'top', this.scrollYOffset() + 'px');
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
unstick() {
|
2016-08-28 21:46:10 +03:00
|
|
|
DOM.setStyle(this.$element, 'top', '0');
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
2016-08-31 23:34:14 +03:00
|
|
|
stickBottom() {
|
|
|
|
DOM.setStyle(this.$element, 'position', 'fixed');
|
|
|
|
var offset = this.scrollY + this.scrollParentHeight - (this.$redocEl.scrollHeight + this.$redocEl.offsetTop);
|
|
|
|
DOM.setStyle(this.$element, 'bottom', offset + 'px');
|
|
|
|
}
|
|
|
|
|
|
|
|
unstickBottom() {
|
|
|
|
DOM.setStyle(this.$element, 'bottom', '0');
|
|
|
|
}
|
|
|
|
|
2015-12-26 20:44:39 +03:00
|
|
|
get scrollY() {
|
2016-06-13 20:54:24 +03:00
|
|
|
return (this.scrollParent.pageYOffset != undefined) ? this.scrollParent.pageYOffset : this.scrollParent.scrollTop;
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
2016-08-31 23:34:14 +03:00
|
|
|
get scrollParentHeight() {
|
|
|
|
return (this.scrollParent.innerHeight != undefined) ? this.scrollParent.innerHeight : this.scrollParent.clientHeight;
|
|
|
|
}
|
|
|
|
|
2015-12-26 20:44:39 +03:00
|
|
|
ngOnInit() {
|
2016-02-10 16:48:07 +03:00
|
|
|
// FIXME use more reliable code
|
2016-08-30 19:35:07 +03:00
|
|
|
this.$redocEl = this.$element.offsetParent.parentNode || DOM.defaultDoc().body;
|
2015-12-26 20:44:39 +03:00
|
|
|
this.bind();
|
2016-11-23 02:23:32 +03:00
|
|
|
requestAnimationFrame(() => this.updatePosition());
|
2015-12-26 20:44:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ngOnDestroy() {
|
|
|
|
this.unbind();
|
|
|
|
}
|
|
|
|
}
|