Change smooth-scroll to check last component instead of Route. Page content sticky base on new uikit version

This commit is contained in:
Konstantinos Triantafyllou 2022-03-14 18:35:00 +02:00
parent c49a79c798
commit 4ccabced6d
3 changed files with 163 additions and 160 deletions

View File

@ -6,26 +6,27 @@ declare var UIkit;
@Component({ @Component({
selector: '[page-content]', selector: '[page-content]',
template: ` template: `
<div id="page_content" [class.sticky]="sticky"> <div id="page_content">
<div #header id="page_content_header"> <div id="header">
<div class="uk-container uk-container-large uk-padding-remove-vertical"> <div #header id="page_content_header" uk-sticky="top: #header; media: @m" [attr.offset]="offset">
<ng-content select="[header]"></ng-content> <div class="uk-container uk-container-large uk-padding-remove-vertical">
<ng-content select="[header]"></ng-content>
</div>
</div> </div>
</div> </div>
<div id="page_content_inner" [class.sticky]="sticky" class="uk-section uk-container uk-container-large"> <div id="page_content_inner" class="uk-section uk-container uk-container-large">
<ng-content select="[inner]"></ng-content> <ng-content select="[inner]"></ng-content>
</div> </div>
</div> </div>
` `,
}) })
export class PageContentComponent implements OnInit, OnDestroy { export class PageContentComponent implements OnInit, OnDestroy {
private current;
private shouldSticky: boolean = false;
public offset: number; public offset: number;
public sticky: boolean = false; public sticky: boolean = false;
@Output() @Output()
public stickyEmitter: EventEmitter<boolean> = new EventEmitter<boolean>(); public stickyEmitter: EventEmitter<boolean> = new EventEmitter<boolean>();
@ViewChild("header") public header: ElementRef; @ViewChild("header") public header: ElementRef;
private current;
private subscriptions: any[] = []; private subscriptions: any[] = [];
constructor() { constructor() {
@ -38,35 +39,33 @@ export class PageContentComponent implements OnInit, OnDestroy {
if (scroll > this.current) { if (scroll > this.current) {
this.offset = 0; this.offset = 0;
} else { } else {
this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--structure-header-height') + 1); this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--structure-header-height'));
} }
if (this.offset !== previous) { if (this.offset !== previous) {
UIkit.sticky(this.header.nativeElement, { this.initSticky();
offset: this.offset
});
} }
this.current = scroll; this.current = scroll;
if(this.current > this.header.nativeElement.offsetTop + this.header.nativeElement.offsetHeight && this.shouldSticky) {
this.sticky = true;
this.stickyEmitter.emit(this.sticky);
}
} }
ngOnInit() { ngOnInit() {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
this.current = window.pageYOffset; this.current = window.pageYOffset;
} }
}
initSticky() {
this.clear();
this.subscriptions.push(UIkit.util.on(document, 'active', '#page_content_header', (): void => { this.subscriptions.push(UIkit.util.on(document, 'active', '#page_content_header', (): void => {
this.shouldSticky = true; this.sticky = true;
this.stickyEmitter.emit(this.sticky);
})); }));
this.subscriptions.push(UIkit.util.on(document, 'inactive', '#page_content_header', (): void => { this.subscriptions.push(UIkit.util.on(document, 'inactive', '#page_content_header', (): void => {
this.sticky = false; this.sticky = false;
this.shouldSticky = false;
this.stickyEmitter.emit(this.sticky); this.stickyEmitter.emit(this.sticky);
})); }));
} }
ngOnDestroy() { clear() {
this.subscriptions.forEach(subscription => { this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscription) { if (subscription instanceof Subscription) {
subscription.unsubscribe(); subscription.unsubscribe();
@ -75,4 +74,8 @@ export class PageContentComponent implements OnInit, OnDestroy {
} }
}); });
} }
ngOnDestroy() {
this.clear();
}
} }

View File

@ -92,148 +92,149 @@
</div> </div>
</div> </div>
</div> </div>
<div class="uk-visible@m"> <div id="main-menu" class="uk-visible@m">
<div class="uk-navbar-transparent" [ngClass]="portal + '-menu'" <div class="uk-navbar-container" [ngClass]="portal + '-menu'"
uk-sticky="show-on-up: true" media="@m" cls-active="uk-active uk-navbar-sticky" uk-sticky="show-on-up: true; top: #main-menu" media="@m" cls-active="uk-active uk-navbar-sticky"
cls-inactive="uk-navbar-transparent"
[attr.animation]="(header.stickyAnimation?'uk-animation-slide-top':null)"> [attr.animation]="(header.stickyAnimation?'uk-animation-slide-top':null)">
<div <div
*ngIf="(properties.environment =='beta' || properties.environment =='development') && showLogo && header.badge"> *ngIf="(properties.environment =='beta' || properties.environment =='development') && showLogo && header.badge">
<img class="uk-position-top-left" <img class="uk-position-top-left"
[src]="'assets/common-assets/'+(properties.environment =='beta'?'beta_flag.svg':'prototype_flag.svg')" [src]="'assets/common-assets/'+(properties.environment =='beta'?'beta_flag.svg':'prototype_flag.svg')"
alt="BETA" style="height: 100px; width: 100px; z-index: 1000"> alt="BETA" style="height: 65px; width: 65px; z-index: 1000">
</div> </div>
<nav class="uk-navbar uk-flex uk-navbar-container uk-padding-large uk-padding-remove-vertical" uk-navbar> <div class="uk-container uk-container-expand">
<ng-container *ngIf="!onlyTop"> <nav class="uk-navbar" uk-navbar>
<div class="uk-navbar-left"> <ng-container *ngIf="!onlyTop">
<ng-container *ngIf="showLogo && isHeaderLeft"> <div class="uk-navbar-left">
<ng-container *ngTemplateOutlet="header_template; context: {mobile: false}"></ng-container> <ng-container *ngIf="showLogo && isHeaderLeft">
</ng-container> <ng-container *ngTemplateOutlet="header_template; context: {mobile: false}"></ng-container>
</div>
<div class="uk-navbar-center">
<ng-container *ngIf="showLogo && !isHeaderLeft">
<ng-container *ngTemplateOutlet="header_template; context: {mobile: false}"></ng-container>
</ng-container>
<ng-container *ngIf="!header.menuPosition || header.menuPosition === 'center'">
<ng-container *ngTemplateOutlet="mainMenu"></ng-container>
</ng-container>
</div>
<div class="uk-navbar-right">
<ng-container *ngIf="header.menuPosition === 'right'">
<ng-container *ngTemplateOutlet="mainMenu"></ng-container>
</ng-container>
<user-mini *ngIf="userMenu" [user]="user" [dark]="dark"
[userMenuItems]=userMenuItems [logInUrl]=properties.loginUrl [logOutUrl]=properties.logoutUrl
[cookieDomain]=properties.cookieDomain></user-mini>
<ng-content select="[extra-m]"></ng-content>
</div>
<ng-template #mainMenu>
<ul class="uk-navbar-nav" [class.uk-margin-right]="!userMenu">
<li class="uk-parent" *ngIf="showHomeMenuItem && currentRoute.route !== '/'">
<a routerLink="/">Home</a>
</li>
<ng-container *ngFor="let menu of menuItems">
<li class="uk-parent" [class.uk-active]="isTheActiveMenu(menu)"
*ngIf="isAtleastOneEnabled(menu.rootItem.entitiesRequired,showEntity) && isAtleastOneEnabled(menu.rootItem.routeRequired, showPage)">
<!--a routerLink="{{menu.rootItem.route}}" [queryParams]=menu.rootItem.params class="" aria-expanded="false">{{menu.rootItem.title}}</a-->
<a *ngIf="menu.rootItem.route.length > 0 && (isEnabled([menu.rootItem.route], showPage) || !menu.rootItem.routeRequired )"
routerLink="{{menu.rootItem.route}}"
[queryParams]="menu.rootItem.params"
[fragment]="menu.rootItem.fragment"> {{menu.rootItem.title}}</a>
<a *ngIf="menu.rootItem.route.length == 0 && menu.rootItem.url.length > 0"
href="{{menu.rootItem.url}}" target="{{menu.rootItem.url.includes('http') ? '_blank' : '_self'}}"
aria-expanded="false">{{menu.rootItem.title}}</a>
<a *ngIf="(menu.rootItem.route.length == 0 && menu.rootItem.url.length == 0) || ( menu.rootItem.route.length >0 && menu.rootItem.routeRequired && !isEnabled([menu.rootItem.route], showPage) && isAtleastOneEnabled(menu.rootItem.routeRequired, showPage))">{{menu.rootItem.title}}</a>
<div *ngIf="menu.items.length > 0" class="uk-navbar-dropdown" uk-drop="pos: bottom-left">
<div class="uk-height-max-medium uk-overflow-auto">
<ul class="uk-nav uk-navbar-dropdown-nav">
<ng-container *ngFor="let submenu of menu.items">
<li *ngIf="isEnabled(submenu.entitiesRequired,showEntity) &&
isEnabled(submenu.routeRequired, showPage) && (submenu.route.length > 0 ||
submenu.url.length > 0)" [class.uk-active]="isTheActiveMenuItem(submenu)"
[class.uk-parent]="submenu.items && submenu.items.length > 0">
<a *ngIf="submenu.route.length > 0"
routerLink="{{submenu.route}}" [queryParams]="submenu.params"
[fragment]="submenu.fragment">{{submenu.title}}</a>
<a *ngIf="submenu.route.length == 0 && submenu.url.length > 0"
href="{{submenu.url}}"
target="{{submenu.url.includes('http') ? '_blank' : '_self'}}">{{submenu.title}}</a>
<ul *ngIf="submenu.items && submenu.items.length > 0" class="uk-nav-sub">
<ng-container *ngFor="let subsubmenu of submenu.items">
<li>
<a *ngIf="subsubmenu.route.length > 0"
routerLink="{{subsubmenu.route}}" [queryParams]="subsubmenu.params"
[fragment]="subsubmenu.fragment">{{subsubmenu.title}}</a>
<a *ngIf="subsubmenu.route.length == 0 && subsubmenu.url.length > 0"
href="{{subsubmenu.url}}" target="_blank">{{subsubmenu.title}}</a>
</li>
</ng-container>
</ul>
<li *ngIf="submenu.route.length == 0 && submenu.url.length == 0 && isEnabled(submenu.entitiesRequired,showEntity) && isEnabled(submenu.routeRequired, showPage)"
class="uk-nav-header">{{submenu.title}}</li>
</ng-container>
</ul>
</div>
</div>
</li>
</ng-container> </ng-container>
<!-- Custom menu items --> </div>
<!-- TODO: Add to mobile menu as well! --> <div class="uk-navbar-center">
<ng-container *ngIf="additionalMenuItems?.length > 0 && properties.environment == 'development'"> <ng-container *ngIf="showLogo && !isHeaderLeft">
<ng-container *ngFor="let menu of additionalMenuItems"> <ng-container *ngTemplateOutlet="header_template; context: {mobile: false}"></ng-container>
<li class="uk-parent"> </ng-container>
<!-- INTERNAL ROOT--> <ng-container *ngIf="!header.menuPosition || header.menuPosition === 'center'">
<a *ngIf="menu.type == 'internal' && menu.route && isEnabled([menu.route], showPage)" <ng-container *ngTemplateOutlet="mainMenu"></ng-container>
routerLink="{{menu.route}}" </ng-container>
[queryParams]="menu.params" </div>
[fragment]="menu.fragment"> <div class="uk-navbar-right">
{{menu.title}} <ng-container *ngIf="header.menuPosition === 'right'">
</a> <ng-container *ngTemplateOutlet="mainMenu"></ng-container>
<!-- EXTERNAL ROOT--> </ng-container>
<a *ngIf="menu.type == 'external' && menu.url" <user-mini *ngIf="userMenu" [user]="user" [dark]="dark"
href="{{menu.url}}" [userMenuItems]=userMenuItems [logInUrl]=properties.loginUrl [logOutUrl]=properties.logoutUrl
target="_blank"> [cookieDomain]=properties.cookieDomain></user-mini>
{{menu.title}} <ng-content select="[extra-m]"></ng-content>
</a> </div>
<!-- NO ACTION ROOT--> <ng-template #mainMenu>
<a *ngIf="menu.type == 'noAction'"> <ul class="uk-navbar-nav" [class.uk-margin-right]="!userMenu">
{{menu.title}} <li class="uk-parent" *ngIf="showHomeMenuItem && currentRoute.route !== '/'">
</a> <a routerLink="/">Home</a>
<div *ngIf="menu.items.length > 0" class="uk-navbar-dropdown uk-navbar-dropdown-bottom-left" </li>
style="top: 80px; left: 0px;" id="{{menu._id}}" uk-toggle> <ng-container *ngFor="let menu of menuItems">
<div class="uk-navbar-dropdown-grid uk-child-width-1-1 uk-grid uk-grid-stack" uk-grid=""> <li class="uk-parent" [class.uk-active]="isTheActiveMenu(menu)"
<div class="uk-first-column uk-height-max-medium uk-overflow-auto"> *ngIf="isAtleastOneEnabled(menu.rootItem.entitiesRequired,showEntity) && isAtleastOneEnabled(menu.rootItem.routeRequired, showPage)">
<ul class="uk-nav uk-navbar-dropdown-nav"> <!--a routerLink="{{menu.rootItem.route}}" [queryParams]=menu.rootItem.params class="" aria-expanded="false">{{menu.rootItem.title}}</a-->
<ng-container *ngFor="let submenu of menu.items"> <a *ngIf="menu.rootItem.route.length > 0 && (isEnabled([menu.rootItem.route], showPage) || !menu.rootItem.routeRequired )"
<li> routerLink="{{menu.rootItem.route}}"
<!-- INTERNAL CHILD --> [queryParams]="menu.rootItem.params"
<a *ngIf="submenu.type == 'internal' && submenu.route && isEnabled([submenu.route], showPage)" [fragment]="menu.rootItem.fragment"> {{menu.rootItem.title}}</a>
routerLink="{{submenu.route}}" <a *ngIf="menu.rootItem.route.length == 0 && menu.rootItem.url.length > 0"
[queryParams]="submenu.params" href="{{menu.rootItem.url}}" target="{{menu.rootItem.url.includes('http') ? '_blank' : '_self'}}"
[fragment]="submenu.fragment" aria-expanded="false">{{menu.rootItem.title}}</a>
[class.uk-active]="isTheActiveMenuItem(submenu)"> <a *ngIf="(menu.rootItem.route.length == 0 && menu.rootItem.url.length == 0) || ( menu.rootItem.route.length >0 && menu.rootItem.routeRequired && !isEnabled([menu.rootItem.route], showPage) && isAtleastOneEnabled(menu.rootItem.routeRequired, showPage))">{{menu.rootItem.title}}</a>
{{submenu.title}} <div *ngIf="menu.items.length > 0" class="uk-navbar-dropdown" uk-drop="pos: bottom-left">
</a> <div class="uk-height-max-medium uk-overflow-auto">
<!-- EXTERNAL CHILD --> <ul class="uk-nav uk-navbar-dropdown-nav">
<a *ngIf="submenu.type == 'external' && submenu.url" <ng-container *ngFor="let submenu of menu.items">
href="{{submenu.url}}" <li *ngIf="isEnabled(submenu.entitiesRequired,showEntity) &&
target="_blank"> isEnabled(submenu.routeRequired, showPage) && (submenu.route.length > 0 ||
{{submenu.title}} submenu.url.length > 0)" [class.uk-active]="isTheActiveMenuItem(submenu)"
</a> [class.uk-parent]="submenu.items && submenu.items.length > 0">
</li> <a *ngIf="submenu.route.length > 0"
</ng-container> routerLink="{{submenu.route}}" [queryParams]="submenu.params"
</ul> [fragment]="submenu.fragment">{{submenu.title}}</a>
</div> <a *ngIf="submenu.route.length == 0 && submenu.url.length > 0"
href="{{submenu.url}}"
target="{{submenu.url.includes('http') ? '_blank' : '_self'}}">{{submenu.title}}</a>
<ul *ngIf="submenu.items && submenu.items.length > 0" class="uk-nav-sub">
<ng-container *ngFor="let subsubmenu of submenu.items">
<li>
<a *ngIf="subsubmenu.route.length > 0"
routerLink="{{subsubmenu.route}}" [queryParams]="subsubmenu.params"
[fragment]="subsubmenu.fragment">{{subsubmenu.title}}</a>
<a *ngIf="subsubmenu.route.length == 0 && subsubmenu.url.length > 0"
href="{{subsubmenu.url}}" target="_blank">{{subsubmenu.title}}</a>
</li>
</ng-container>
</ul>
<li *ngIf="submenu.route.length == 0 && submenu.url.length == 0 && isEnabled(submenu.entitiesRequired,showEntity) && isEnabled(submenu.routeRequired, showPage)"
class="uk-nav-header">{{submenu.title}}</li>
</ng-container>
</ul>
</div> </div>
</div> </div>
</li> </li>
</ng-container> </ng-container>
</ng-container> <!-- Custom menu items -->
</ul> <!-- TODO: Add to mobile menu as well! -->
</ng-template> <ng-container *ngIf="additionalMenuItems?.length > 0 && properties.environment == 'development'">
</ng-container> <ng-container *ngFor="let menu of additionalMenuItems">
</nav> <li class="uk-parent">
<!-- INTERNAL ROOT-->
<a *ngIf="menu.type == 'internal' && menu.route && isEnabled([menu.route], showPage)"
routerLink="{{menu.route}}"
[queryParams]="menu.params"
[fragment]="menu.fragment">
{{menu.title}}
</a>
<!-- EXTERNAL ROOT-->
<a *ngIf="menu.type == 'external' && menu.url"
href="{{menu.url}}"
target="_blank">
{{menu.title}}
</a>
<!-- NO ACTION ROOT-->
<a *ngIf="menu.type == 'noAction'">
{{menu.title}}
</a>
<div *ngIf="menu.items.length > 0" class="uk-navbar-dropdown uk-navbar-dropdown-bottom-left"
style="top: 80px; left: 0px;" id="{{menu._id}}" uk-toggle>
<div class="uk-navbar-dropdown-grid uk-child-width-1-1 uk-grid uk-grid-stack" uk-grid="">
<div class="uk-first-column uk-height-max-medium uk-overflow-auto">
<ul class="uk-nav uk-navbar-dropdown-nav">
<ng-container *ngFor="let submenu of menu.items">
<li>
<!-- INTERNAL CHILD -->
<a *ngIf="submenu.type == 'internal' && submenu.route && isEnabled([submenu.route], showPage)"
routerLink="{{submenu.route}}"
[queryParams]="submenu.params"
[fragment]="submenu.fragment"
[class.uk-active]="isTheActiveMenuItem(submenu)">
{{submenu.title}}
</a>
<!-- EXTERNAL CHILD -->
<a *ngIf="submenu.type == 'external' && submenu.url"
href="{{submenu.url}}"
target="_blank">
{{submenu.title}}
</a>
</li>
</ng-container>
</ul>
</div>
</div>
</div>
</li>
</ng-container>
</ng-container>
</ul>
</ng-template>
</ng-container>
</nav>
</div>
</div> </div>
<!-- New navbar for featured menu items - test only --> <!-- New navbar for featured menu items - test only -->
<ng-container *ngIf="featuredMenuItems?.length > 0 && properties.environment == 'development'"> <ng-container *ngIf="featuredMenuItems?.length > 0 && properties.environment == 'development'">

View File

@ -1,4 +1,4 @@
import {NavigationEnd, Router} from '@angular/router'; import {ActivationStart, NavigationEnd, Router} from '@angular/router';
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {Subscription} from 'rxjs'; import {Subscription} from 'rxjs';
@ -8,17 +8,20 @@ import {Subscription} from 'rxjs';
export class SmoothScroll { export class SmoothScroll {
private interval; private interval;
private readonly sub; private readonly sub;
private lastRoute; private lastComponent;
private currentComponent: any;
constructor(private router: Router) { constructor(private router: Router) {
if(typeof window !== "undefined") { if (typeof window !== "undefined") {
this.sub = router.events.subscribe(event => { this.sub = router.events.subscribe(event => {
if (event instanceof NavigationEnd) { if (event instanceof ActivationStart) {
this.currentComponent = event.snapshot.component;
} else if (event instanceof NavigationEnd) {
if (this.interval) { if (this.interval) {
clearInterval(this.interval); clearInterval(this.interval);
} }
const fragment = router.parseUrl(router.url).fragment; const fragment = router.parseUrl(router.url).fragment;
if (this.lastRoute !== this.getUrl(event.url)) { if (this.lastComponent !== this.currentComponent) {
window.scrollTo({top: 0}); window.scrollTo({top: 0});
} }
if (fragment) { if (fragment) {
@ -49,16 +52,12 @@ export class SmoothScroll {
} else { } else {
window.scrollTo({top: 0, behavior: 'smooth'}); window.scrollTo({top: 0, behavior: 'smooth'});
} }
this.lastRoute = this.getUrl(event.url); this.lastComponent = this.currentComponent;
} }
}); });
} }
} }
private getUrl(url: string) {
return url.split('?')[0].split('#')[0];
}
public clearSubscriptions() { public clearSubscriptions() {
if (this.sub && this.sub instanceof Subscription) { if (this.sub && this.sub instanceof Subscription) {
this.sub.unsubscribe(); this.sub.unsubscribe();