redoc/lib/shared/components/StickySidebar/sticky-sidebar.ts

101 lines
2.6 KiB
TypeScript
Raw Normal View History

2015-12-26 20:44:39 +03:00
'use strict';
2017-06-14 11:12:07 +03:00
import { Directive, ElementRef, Input, OnInit, OnDestroy, OnChanges} 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({
selector: '[sticky-sidebar]'
2015-12-26 20:44:39 +03:00
})
2017-06-14 11:12:07 +03:00
export class StickySidebar implements OnInit, OnDestroy, OnChanges {
$element: any;
cancelScrollBinding: any;
$redocEl: any;
@Input() scrollParent:any;
@Input() scrollYOffset:any;
@Input() disable:any;
2016-06-13 20:54:24 +03:00
2016-08-28 21:46:10 +03:00
constructor(elementRef:ElementRef) {
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() {
var stuck = false;
if ( this.scrollY + this.scrollYOffset() >= this.$redocEl.offsetTop && !this.disable) {
2015-12-26 20:44:39 +03:00
this.stick();
stuck = true;
2015-12-26 20:44:39 +03:00
} else {
this.unstick();
}
if ( this.scrollY + window.innerHeight - this.scrollYOffset()
>= this.$redocEl.scrollHeight && !this.disable) {
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
}
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
}
get scrollParentHeight() {
return (this.scrollParent.innerHeight != undefined) ? this.scrollParent.innerHeight : this.scrollParent.clientHeight;
}
2015-12-26 20:44:39 +03:00
ngOnInit() {
// 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
}
2017-06-14 11:12:07 +03:00
ngOnChanges() {
2017-06-14 11:27:50 +03:00
if (!this.$redocEl || this.disable) return;
2017-06-14 11:12:07 +03:00
this.updatePosition();
}
2015-12-26 20:44:39 +03:00
ngOnDestroy() {
this.unbind();
}
}