227 lines
7.5 KiB
TypeScript
227 lines
7.5 KiB
TypeScript
import {
|
|
AfterViewInit,
|
|
ChangeDetectorRef,
|
|
Component,
|
|
ElementRef,
|
|
Inject,
|
|
Input,
|
|
OnDestroy,
|
|
OnInit,
|
|
PLATFORM_ID,
|
|
ViewChild
|
|
} from "@angular/core";
|
|
import {LayoutService, SidebarItem} from "../sidebar/layout.service";
|
|
|
|
declare var UIkit;
|
|
|
|
@Component({
|
|
selector: '[page-content]',
|
|
template: `
|
|
<div id="page_content">
|
|
<div [class.uk-hidden]="!isBrowser" id="page_content_sticky_footer" #sticky_footer
|
|
class="uk-tile-default uk-blur-background">
|
|
<div class="uk-container uk-container-large">
|
|
<div [ngClass]="!isMobile?'uk-padding-small uk-padding-remove-vertical':''">
|
|
<ng-content select="[sticky_footer]"></ng-content>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="page_content_header" #header class="uk-blur-background" [class.uk-border-bottom]="border && isStickyActive"
|
|
[attr.style]="'margin-top: '+(footer_height? '-'+footer_height+'px': '0')">
|
|
<div class="uk-container uk-container-large">
|
|
<div [ngClass]="!isMobile?'uk-padding-small uk-padding-remove-vertical uk-padding-remove-right':''">
|
|
<ng-content select="[header]"></ng-content>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="page_content_actions" #actions class="uk-blur-background" [class.uk-border-bottom]="border && isStickyActive">
|
|
<div class="uk-container uk-container-large">
|
|
<div [ngClass]="!isMobile?'uk-padding-small uk-padding-remove-vertical uk-padding-remove-right':''">
|
|
<ng-content select="[actions]"></ng-content>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="page_content_inner" class="uk-container uk-container-large">
|
|
<div [ngClass]="!isMobile?'uk-padding-small uk-padding-remove-vertical':''">
|
|
<ng-content select="[inner]"></ng-content>
|
|
</div>
|
|
</div>
|
|
<div id="page_content_footer" #footer>
|
|
<div class="uk-container uk-container-large">
|
|
<div [ngClass]="!isMobile?'uk-padding-small uk-padding-remove-vertical':''">
|
|
<ng-content select="[footer]"></ng-content>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
})
|
|
export class PageContentComponent implements OnInit, AfterViewInit, OnDestroy {
|
|
@Input()
|
|
public headerSticky: boolean = false;
|
|
@Input()
|
|
public border: boolean = true;
|
|
public offset: number;
|
|
public shouldSticky: boolean = true;
|
|
public isMobile: boolean = false;
|
|
public isStickyActive: boolean = false;
|
|
public footer_height: number = 0;
|
|
@ViewChild('header') header: ElementRef;
|
|
@ViewChild('actions') actions: ElementRef;
|
|
@ViewChild("sticky_footer") sticky_footer: ElementRef;
|
|
private sticky = {
|
|
header: null,
|
|
footer: null
|
|
}
|
|
subscriptions = [];
|
|
|
|
constructor(private layoutService: LayoutService, private cdr: ChangeDetectorRef,
|
|
@Inject(PLATFORM_ID) private platformId) {
|
|
}
|
|
|
|
ngOnInit() {
|
|
if(this.isBrowser) {
|
|
this.stickyBugWorkaround();
|
|
}
|
|
this.subscriptions.push(this.layoutService.isMobile.subscribe(isMobile => {
|
|
this.isMobile = isMobile;
|
|
if(this.isBrowser) {
|
|
this.offset = this.isMobile?0:Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height'));
|
|
}
|
|
this.cdr.detectChanges();
|
|
}));
|
|
}
|
|
|
|
get isBrowser() {
|
|
return this.platformId === 'browser';
|
|
}
|
|
|
|
ngAfterViewInit() {
|
|
if (typeof document !== "undefined") {
|
|
if (this.sticky_footer) {
|
|
this.initFooter();
|
|
this.observeStickyFooter();
|
|
}
|
|
if (this.shouldSticky && typeof document !== 'undefined') {
|
|
setTimeout(() => {
|
|
this.sticky.header = UIkit.sticky((this.headerSticky ? this.header.nativeElement : this.actions.nativeElement), {
|
|
offset: this.offset
|
|
});
|
|
this.subscriptions.push(UIkit.util.on(document, 'active', '#' + this.sticky.header.$el.id, () => {
|
|
this.isStickyActive = true;
|
|
this.cdr.detectChanges();
|
|
}));
|
|
this.subscriptions.push(UIkit.util.on(document, 'inactive', '#' + this.sticky.header.$el.id, () => {
|
|
this.isStickyActive = false;
|
|
this.cdr.detectChanges();
|
|
}));
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
this.subscriptions.forEach(subscription => {
|
|
if (typeof ResizeObserver !== "undefined" && subscription instanceof ResizeObserver) {
|
|
subscription.disconnect();
|
|
} else if (typeof IntersectionObserver !== "undefined" && subscription instanceof IntersectionObserver) {
|
|
subscription.disconnect();
|
|
}
|
|
});
|
|
}
|
|
|
|
initFooter() {
|
|
let footer_offset = this.calcStickyFooterOffset(this.sticky_footer.nativeElement);
|
|
this.sticky.footer = UIkit.sticky(this.sticky_footer.nativeElement, {bottom: true, offset: footer_offset});
|
|
}
|
|
|
|
/**
|
|
* Workaround for sticky not update bug when sidebar is toggled.
|
|
* TODO when UIKit will be updated => remove
|
|
*
|
|
* */
|
|
stickyBugWorkaround() {
|
|
let sidebarOffset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--dashboard-sidebar-width')) -
|
|
Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--dashboard-sidebar-mini-width'));
|
|
let transitionDelay = Number.parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--dashboard-transition-delay')) * 1000;
|
|
this.subscriptions.push(this.layoutService.isOpen.subscribe(isOpen => {
|
|
if (this.sticky.header) {
|
|
if (isOpen) {
|
|
this.sticky.header.$el.style.width = Number.parseInt(this.sticky.header.$el.style.width) - sidebarOffset + 'px';
|
|
} else {
|
|
this.sticky.header.$el.style.width = Number.parseInt(this.sticky.header.$el.style.width) + sidebarOffset + 'px';
|
|
}
|
|
setTimeout(() => {
|
|
this.sticky.header.$emit();
|
|
}, transitionDelay);
|
|
}
|
|
if (this.sticky.footer) {
|
|
if (isOpen) {
|
|
this.sticky.footer.$el.style.width = Number.parseInt(this.sticky.footer.$el.style.width) - sidebarOffset + 'px';
|
|
} else {
|
|
this.sticky.footer.$el.style.width = Number.parseInt(this.sticky.footer.$el.style.width) + sidebarOffset + 'px';
|
|
}
|
|
setTimeout(() => {
|
|
this.sticky.footer.$emit();
|
|
}, transitionDelay);
|
|
}
|
|
this.cdr.detectChanges();
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
*
|
|
* Should be smooth
|
|
*
|
|
* */
|
|
private observeBottom() {
|
|
let bottom = document.getElementById('bottom');
|
|
if (bottom) {
|
|
let bottomObs = new IntersectionObserver(entries => {
|
|
entries.forEach(entry => {
|
|
this.shouldSticky = !entry.isIntersecting;
|
|
})
|
|
});
|
|
this.subscriptions.push(bottomObs);
|
|
bottomObs.observe(bottom);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* */
|
|
private observeHeader() {
|
|
if (this.header) {
|
|
let headerObs = new IntersectionObserver(entries => {
|
|
entries.forEach(entry => {
|
|
if (entry.boundingClientRect.height > 0) {
|
|
this.layoutService.setReplaceHeader(!entry.isIntersecting);
|
|
}
|
|
})
|
|
});
|
|
this.subscriptions.push(headerObs);
|
|
headerObs.observe(this.header.nativeElement);
|
|
}
|
|
}
|
|
|
|
private observeStickyFooter() {
|
|
if (this.sticky_footer) {
|
|
let resizeObs = new ResizeObserver(entries => {
|
|
entries.forEach(entry => {
|
|
setTimeout(() => {
|
|
this.initFooter();
|
|
});
|
|
})
|
|
});
|
|
this.subscriptions.push(resizeObs);
|
|
resizeObs.observe(this.sticky_footer.nativeElement);
|
|
}
|
|
}
|
|
|
|
calcStickyFooterOffset(element) {
|
|
this.footer_height = element.offsetHeight;
|
|
return window.innerHeight - this.footer_height;
|
|
}
|
|
}
|