File
Implements
Metadata
selector |
rich-text-field |
styleUrls |
./rich-text-field.component.scss |
templateUrl |
./rich-text-field.component.html |
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Methods
Public
anchorClick
|
anchorClick(event, templateRef)
|
|
Parameters :
Name |
Optional |
event |
No
|
templateRef |
No
|
|
Private
openModal
|
openModal(templateRef)
|
|
Parameters :
Name |
Optional |
templateRef |
No
|
|
Private
resolveColor
|
resolveColor()
|
|
|
color
|
Type : RichTextColor
|
Default value : 'text-darker-green-grey'
|
|
id
|
Default value : this.idGenerator.getId()
|
|
modalContentText
|
Type : string
|
Default value : ''
|
|
modalType
|
Type : "IMAGE" | "TABLE"
|
|
import { Component, OnInit, Input } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { HttpClient } from '@angular/common/http';
import { UtilService } from 'src/app/core/services/util-service/util.service';
import { PublicationService } from 'src/app/core/services/publication-service/publication.service';
import { IdGeneratorService } from 'src/app/core/services/id-generator.service';
import { ExpandService } from '../../../core/services/expand-service/expand.service';
type RichTextColor = 'text-white' | 'text-darker-green-grey';
interface TabelData {
body;
footer;
}
@Component({
selector: 'rich-text-field',
templateUrl: './rich-text-field.component.html',
styleUrls: ['./rich-text-field.component.scss']
})
export class RichTextFieldComponent implements OnInit {
@Input() body;
@Input() textColor: string;
color: RichTextColor = 'text-darker-green-grey';
/*
This id is used to have a unique (hopefully) name for the modal window
to not cause issue if multiple modal links are added on the same page
*/
id = this.idGenerator.getId();
// These two are set when a user clicks on a link that should open a modal
modalContentSrc: string;
modalContentText = '';
modalType: 'IMAGE' | 'TABLE';
tableData: TabelData;
constructor(
private modalService: NgbModal,
private http: HttpClient,
private util: UtilService,
private publicationService: PublicationService,
private idGenerator: IdGeneratorService,
private expandService: ExpandService
) { }
ngOnInit() {
this.color = this.resolveColor();
}
// Handles anchor refs and scrolls to the linked element.
public anchorClick(event, templateRef) {
const href = event.target.getAttribute('href');
// handle only hrefs to internal links
if ( href && href.charAt(0) === '#') {
const anchor = href.substring(1);
const element = document.getElementById(anchor);
if (element) {
const card = element.closest('.card');
// For body text expandable we need to open the accordion before scrolling.
if (card) {
const cardHeader = card.querySelector('.card-header');
const accordionId = cardHeader.getAttribute('id').replace('-header', '');
this.expandService.openAccordion(accordionId);
}
element.scrollIntoView({ behavior: 'smooth' });
}
return false;
}
const tagThatWasClicked = event.target.closest('.modal-window');
if (tagThatWasClicked !== null) {
// Don't follow the link that was clicked
event.preventDefault();
this.modalContentSrc = tagThatWasClicked.href;
// If href contains tcm-id, set modal type to Table, otherwise Image
if (this.modalContentSrc.startsWith('tcm:')) {
this.modalType = 'TABLE';
this.modalContentSrc = this.modalContentSrc.split('-')[1];
// Get table data
this.http.get(`/content${this.publicationService.getPublicationPath()}/dynamicComponent?itemId=${this.modalContentSrc}`).toPromise().then(res => {
this.tableData = {
body: this.util.extract(res, 'Content', 'table'),
footer: this.util.extract(res, 'Content', 'footnotes')
};
this.modalContentText = tagThatWasClicked.text + ' - ' + (this.util.extract(res, 'Content', 'title') || '');
});
} else {
this.modalType = 'IMAGE';
this.modalContentText = tagThatWasClicked.text + ' - ' + tagThatWasClicked.title;
}
this.openModal(templateRef);
}
}
// Passed the template ref that is set the html template
private openModal(templateRef): void {
this.modalService.open(templateRef, { windowClass: 'modal-60-percent', size: 'lg', centered: true });
}
private resolveColor(): RichTextColor {
switch (this.textColor) {
case 'white': return 'text-white';
case 'darker-green-grey': return 'text-darker-green-grey';
}
return 'text-darker-green-grey';
}
}
<div [ngClass]="['content', color]" *ngIf="body">
<div (click)="anchorClick($event, id)" [innerHTML]="body | safeHTML"></div>
</div>
<ng-template #id let-modal>
<div [ngClass]="{'catalogue-table': modalType==='TABLE'}">
<div class="modal-header">
<h4 class="modal-title"> {{modalContentText}} </h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span >×</span>
</button>
</div>
<div class="modal-body">
<img [src]="modalContentSrc" *ngIf="modalType==='IMAGE'">
<div class="table-responsive" *ngIf="modalType==='TABLE' && tableData?.body">
<rich-text-field [body]="tableData.body"></rich-text-field>
</div>
</div>
<div class="modal-footer" *ngIf="modalType==='TABLE' && tableData?.footer">
<ol class="note-list">
<li class="d-flex" *ngFor="let footer of tableData.footer; let i=index">
<span class="mr-1"><sup>{{i+1}})</sup></span>
<rich-text-field [body]="footer"></rich-text-field>
</li>
</ol>
</div>
</div>
</ng-template>
@import "src/app/styles/helpers";
:host .content {
::ng-deep {
font-family: 'SKF Chevin OT Light';
}
@include clearfix;
::ng-deep img {
// This is used to override the sizes set by editors in RTFs in tridion
// We set the max-width to not cause the image to span over the screen width
// height is unset to keep the image scaled reasonably
max-width: 100%;
height: unset !important;
}
// This is needed since the html is embedded
// Make the anchor tag look as if it where a regular link
::ng-deep .embeddedAnchor {
color: $blue;
&:hover {
text-decoration: underline;
color: #0056b3;
}
}
::ng-deep .small-capital-heading {
@include font-scale(18, medium);
font-variant: small-caps;
font-variant-caps: all-small-caps;
}
::ng-deep {
.colorful-and-striped {
border: none !important;
caption {
caption-side: top;
color: $cool-grey;
@include font-scale(14, uppercase);
}
thead tr {
th, td {
border: none;
color: $white;
background-color: $blue;
@include font-scale(14, demibold);
& a {
color: $light-blue;
}
}
&:nth-last-child(2) {
th, td {
border-bottom: 1px solid $dark-blue !important;
}
}
&:last-child {
th, td {
border-bottom: 2px solid $dark-blue !important;
}
}
}
tbody tr {
td {
border: none;
@include font-scale(14, light);
}
&:nth-child(odd) {
background-color: $off-white;
}
&:nth-child(even) {
background-color: $white;
}
}
}
.simple-tables {
@extend .colorful-and-striped;
th, td {
color: inherit;
background-color: $white !important;
& a {
color: $blue;
}
}
tr {
background-color: $white !important;
}
.thin-table-border {
border-bottom: 1px solid $cool-grey;
}
.thick-table-border {
border-bottom: 2px solid $cool-grey;
}
}
.no-colors {
background-color: $off-white;
border-left: 0px;
border-right: 0px;
caption {
caption-side: top;
color: $cool-grey;
@include font-scale(14, uppercase);
}
tbody {
tr {
td {
height: 24px;
@include font-scale(16, light);
color: $cool-grey;
padding-top: 12px;
padding-bottom: 9px;
border-left: 0px;
border-right: 0px;
}
}
tr:first-child {
border-top: 3px solid;
border-top-color: $cool-grey;
}
}
}
}
}
.text-white {
::ng-deep {
color: white;
h1 { color: white; }
h2 { color: white; }
h3 { color: white; }
h4 { color: white; }
h5 { color: white; }
p { color: white; }
a {
color: white;
text-decoration: underline;
}
}
}
.text-darker-green-grey {
::ng-deep {
color: $cool-grey;
h1 {color: $cool-grey;}
h2 {color: $cool-grey;}
h3 {color: $cool-grey;}
h4 {color: $cool-grey;}
h5 {color: $cool-grey;}
p {color: $cool-grey;}
}
}
// Used for the modal window. Move to global allow global usablity later
.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;
}
@include media-breakpoint-up(xl) {
max-width: 45%;
}
}
.modal-body {
img {
max-width: 100%;
object-fit: fill;
}
}
.modal-footer {
justify-content: flex-start;
align-items: flex-start;
}
.modal-content {
margin: 0 auto;
}
}
::ng-deep .catalogue-table {
.modal-header { background-color: $off-white; }
.modal-body { background-color: $off-white; }
.modal-footer {
background-color: $off-white;
@include font-size(12);
align-items: flex-start;
.note-list {
padding-left: 0;
list-style: none;
margin: 0;
}
}
}
:host ::ng-deep .caution-text, :host ::ng-deep .warning-text {
padding: calc-rem(30);
color: $cool-grey !important;
margin-bottom: calc-rem(20);
h2, h3, h4, h5 {
margin-bottom: 0 !important;
}
h5 {
font-family: 'SKF Chevin OT Light' !important;
font-weight: 300 !important;
}
a {
color: $blue !important;
text-decoration: none !important;
&:hover {
text-decoration: underline !important;
}
}
}
:host ::ng-deep .caution-text {
background-color: tint($orange, 85%);
h2, h3, h4, h5 {
color: $orange !important;
}
}
:host ::ng-deep .warning-text {
background-color: tint($red, 85%);
h2, h3, h4, h5 {
color: $red !important;
}
}
Legend
Html element with directive