File
Implements
Metadata
selector |
div[shortcuts-main] |
styleUrls |
./shortcuts-main.component.scss |
templateUrl |
./shortcuts-main.component.html |
Index
Properties
|
|
Methods
|
|
Inputs
|
|
HostBindings
|
|
Methods
actOnResize
|
actOnResize()
|
|
|
inDesktopView
|
inDesktopView(width: number)
|
|
Parameters :
Name |
Type |
Optional |
width |
number
|
No
|
|
ngOnChanges
|
ngOnChanges()
|
|
|
ngOnDestroy
|
ngOnDestroy()
|
|
|
Private
parseJson
|
parseJson(entity)
|
|
|
Private
parseShortcut
|
parseShortcut(jsonShortcut)
|
|
Parameters :
Name |
Optional |
jsonShortcut |
No
|
|
scroll
|
scroll(target, index)
|
|
Parameters :
Name |
Optional |
target |
No
|
index |
No
|
|
Private
setSelectedShortcut
|
setSelectedShortcut(index)
|
|
|
toggleMobileMenu
|
toggleMobileMenu()
|
|
|
Private
componentId
|
Default value : this.idGenerator.getId()
|
|
Private
Readonly
labelKey
|
Type : string
|
Default value : 'shortcutsJumpToSection'
|
|
Private
subscriptions
|
Type : Subscription[]
|
Default value : []
|
|
import { Component, OnInit, Input, OnDestroy, Inject, ChangeDetectorRef, HostBinding } from '@angular/core';
import { Subscription } from 'rxjs';
import { ConstantsService } from 'src/app/shared/constants/constants.service';
import { LabelService } from 'src/app/core/services/label-service/label-service.service';
import { UtilService } from 'src/app/core/services/util-service/util.service';
import { DOCUMENT } from '@angular/common';
import { ResizeContentService } from 'src/app/core/services/resize-service/resize-content.service';
import { IdGeneratorService } from 'src/app/core/services/id-generator.service';
interface ShortCutsData {
mobileMenuOpen: boolean;
jumpToSectionLabel: string;
shortcuts: Shortcut[];
}
interface Shortcut {
title: string;
target: string;
selected: boolean;
}
@Component({
selector: 'div[shortcuts-main]',
templateUrl: './shortcuts-main.component.html',
styleUrls: ['./shortcuts-main.component.scss']
})
export class ShortcutsMainComponent implements OnInit, OnDestroy {
data: ShortCutsData;
private readonly labelKey = 'shortcutsJumpToSection';
private subscriptions: Subscription[] = [];
desktopView: boolean;
previousWidth: number;
private componentId = this.idGenerator.getId();
@Input() entity;
@HostBinding('class') get class() { return 'bg-off-white'; }
constructor(
private label: LabelService,
private util: UtilService,
private constants: ConstantsService,
private changeDetector: ChangeDetectorRef,
private resizer: ResizeContentService,
private idGenerator: IdGeneratorService,
@Inject(DOCUMENT) private document) { }
ngOnInit() {
this.setup();
}
setup() {
if (this.entity) {
this.data = this.parseJson(this.entity);
this.setLabel(this.data);
const width = (window.innerWidth || this.document.documentElement.clientWidth);
this.desktopView = this.inDesktopView(width);
this.previousWidth = (window.innerWidth || this.document.documentElement.clientWidth);
this.resizer.registerCallback(this.componentId, () => this.actOnResize());
}
}
ngOnChanges() {
this.data = this.parseJson(this.entity);
this.setLabel(this.data);
}
actOnResize(): void {
const currentWidth = window.innerWidth || this.document.documentElement.clientWidth;
this.desktopView = this.inDesktopView(currentWidth);
const inMobile = currentWidth <= this.constants.BOOTSTRAP_BREAKPOINTS.MD;
const previousWasTablet = this.previousWidth > this.constants.BOOTSTRAP_BREAKPOINTS.MD;
// Close if it is not in the mobile view or the broswer is transitioning from non-mobile to mobile
if ((!inMobile) || (previousWasTablet && inMobile)) {
this.data.mobileMenuOpen = false;
}
this.previousWidth = currentWidth;
this.changeDetector.detectChanges();
}
ngOnDestroy(): void {
this.resizer.destroyCallback(this.componentId);
}
// called from the template
toggleMobileMenu(): void {
this.data.mobileMenuOpen = !this.data.mobileMenuOpen;
}
// called from the template
scroll(target, index): void {
// Target is the tcm id from tridion, appending component prefix to match what is set by dxa-entity
target = `${this.constants.COMPONENT_ID_PREFIX}-${target}`;
const scrollTarget = document.getElementById(target);
if (scrollTarget) {
this.setSelectedShortcut(index);
scrollTarget.scrollIntoView({behavior: 'smooth'});
if (!this.desktopView) {
this.toggleMobileMenu();
}
}
}
// set the shortcut that was clicked to selected, all others to false
private setSelectedShortcut(index): void {
this.data.shortcuts.forEach( shortcut => shortcut.selected = false);
this.data.shortcuts[index].selected = true;
}
private setLabel(data: ShortCutsData): void {
this.subscriptions.push(this.label.getValue(this.labelKey).subscribe(label => data.jumpToSectionLabel = label));
}
private parseJson(entity): ShortCutsData {
const shortcuts: Shortcut[] = (this.util.extract(entity, 'ShortcutLink') || []).map(e => this.parseShortcut(e));
const parsed: ShortCutsData = {
mobileMenuOpen: false,
jumpToSectionLabel: '',
shortcuts: shortcuts
};
return parsed;
}
private parseShortcut(jsonShortcut): Shortcut {
const title = this.util.extract(jsonShortcut, 'Title');
const target = this.util.extract(jsonShortcut, 'LinkedComponentId');
const parsed = {
title: title,
target: target,
selected: false
};
return parsed;
}
inDesktopView(width: number): boolean {
return width > this.constants.BOOTSTRAP_BREAKPOINTS.MD;
}
}
<div class="container">
<div class="content" *ngIf="data">
<div class="mobile-menu">
<div class="menu-option" (click)="toggleMobileMenu()">
<div class="shortcut-label">
{{data.jumpToSectionLabel | uppercase}}
</div>
<i *ngIf="!data.mobileMenuOpen" class="icon-chevronDown"></i>
<i *ngIf="data.mobileMenuOpen" class="icon-chevronUp"></i>
</div>
</div>
<div *ngIf="desktopView || data.mobileMenuOpen" class="shortcuts">
<div [ngClass]="{'shortcut': true,
'shortcut-open': data.mobileMenuOpen,
'shortcut-selected': shortcut.selected }"
*ngFor="let shortcut of data.shortcuts; let i = index"
(click)="scroll(shortcut.target,i)">
<a>
{{shortcut.title | uppercase }}
</a>
</div>
</div>
</div>
</div>
@import "src/app/styles/helpers";
.content {
>.mobile-menu {
@include media-breakpoint-up(md) {
display: none;
}
>.menu-option {
margin-bottom: calc-rem(3);
display: flex;
justify-content: space-between;
align-items: center;
padding: calc-rem(28) 0;
padding-right: calc-rem(32);
width: 100%;
color: $cool-grey;
cursor: pointer;
>.shortcut-label {
@include font-scale(14, uppercase);
letter-spacing: calc-rem(0.4);
}
i {
// add a margin here since the actual icon is bigger than the div so the overflows the box
// unless we add this margin
margin-right: calc-rem(20);
@include font-size(7);
}
}
}
.shortcuts {
display: flex;
flex-wrap: wrap;
.shortcut {
@include media-breakpoint-down(sm) {
justify-content: left;
width: 100%
}
display: flex;
justify-content: left;
align-items: center;
padding: calc-rem(28) calc-rem(32);
@include font-scale(14, uppercase);
letter-spacing: calc-rem(0.4);
color: $cool-grey;
cursor: pointer;
&-open {
padding-left: 0;
padding-bottom: 0;
&:last-of-type {
padding-bottom: calc-rem(28);
}
}
}
.shortcut-selected {
@include media-breakpoint-up(md) {
background-color: darken($off-white, 5%);
}
@include media-breakpoint-down(sm) {
font-weight: bold;
width: 100%
}
}
}
}
.close {
&:focus {
outline: none;
}
}
::ng-deep .modal.modal-60-percent {
.modal-dialog {
@include media-breakpoint-up(sm) {
max-width: 60%;
}
@include media-breakpoint-down(sm) {
max-width: 60%;
margin: auto;
}
}
}
Legend
Html element with directive